All Downloads are FREE. Search and download functionalities are using the official Maven repository.

test.junit.fedora.server.resourceIndex.ResourceIndexIntegrationTest Maven / Gradle / Ivy

Go to download

The Fedora Client is a Java Library that allows API access to a Fedora Repository. The client is typically one part of a full Fedora installation.

The newest version!
package fedora.server.resourceIndex;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import org.apache.log4j.Logger;

import org.jrdf.graph.ObjectNode;
import org.jrdf.graph.PredicateNode;
import org.jrdf.graph.SubjectNode;
import org.jrdf.graph.Triple;

import org.trippi.RDFFormat;
import org.trippi.RDFUtil;
import org.trippi.TripleIterator;
import org.trippi.TriplestoreConnector;

import fedora.server.storage.BDefReader;
import fedora.server.storage.BMechReader;
import fedora.server.storage.ConnectionPool;
import fedora.server.storage.DOReader;
import fedora.server.storage.MockRepositoryReader;
import fedora.server.storage.SimpleBDefReader;
import fedora.server.storage.SimpleBMechReader;
import fedora.server.storage.SimpleDOReader;

import fedora.server.storage.translation.DOTranslationUtility;
import fedora.server.storage.translation.FOXMLDOSerializer;
import fedora.server.storage.translation.FOXMLDODeserializer;

import fedora.server.storage.types.BasicDigitalObject;
import fedora.server.storage.types.Datastream;
import fedora.server.storage.types.DatastreamXMLMetadata;
import fedora.server.storage.types.DatastreamManagedContent;
import fedora.server.storage.types.DatastreamReferencedContent;
import fedora.server.storage.types.DigitalObject;
import fedora.server.storage.types.Disseminator;
import fedora.server.storage.types.DSBindingMap;
import fedora.server.storage.types.DSBinding;

/**
 * Superclass for ResourceIndex integration tests.
 *
 * @author [email protected]
 */
public abstract class ResourceIndexIntegrationTest {

    private static final Logger LOG = 
            Logger.getLogger(ResourceIndexIntegrationTest.class.getName());

    private static final String TEST_DIR    = "build/junit";

    private static final String DB_DRIVER   = "org.apache.derby.jdbc.EmbeddedDriver";

    private static final String DB_URL      = "jdbc:derby:test;create=true";

    private static final String DB_USERNAME = "test";

    private static final String DB_PASSWORD = "test";

    // needs to be set in order for object serializers/deserializers to work
    static {
        Datastream.defaultChecksumType = "DISABLED";
    }

    /**
     * The ResourceIndexImpl instance we'll be using.
     */
    private ResourceIndex _ri;

    /**
     * The flusher instance we'll use.
     */
    private Flusher _flusher;

    /**
     * Where to get DB connections from.
     */
    private static ConnectionPool _dbPool;

    // Test setUp

    /**
     * Prepare for testing by instantiating a fresh 
     * ResourceIndexImpl.
     *
     * @throws Exception if setup fails for any reason.
     */
    @BeforeClass
    public static void setUpClass() throws Exception {

        System.setProperty("derby.system.home", TEST_DIR + "/derby");

        // set up the db pool
        _dbPool = new ConnectionPool(DB_DRIVER, DB_URL, DB_USERNAME, 
                DB_PASSWORD, 20, 5, -1L, 0, -1L, 3, -1L, false, false, false, 
                (byte) 1);

        // set up the tables needed by the ri
        Connection conn = _dbPool.getConnection();
        Statement st = conn.createStatement();
        st.executeUpdate("CREATE TABLE riMethod (\n"
                       + "  methodId   VARCHAR(255) NOT NULL,\n"
                       + "  bDefPid    VARCHAR(255) NOT NULL,\n"
                       + "  methodName VARCHAR(255) NOT NULL\n"
                       + ")");
        st.executeUpdate("CREATE INDEX riMethod_bDefPid ON riMethod(bDefPid)");

        st.executeUpdate("CREATE TABLE riMethodImpl (\n"
                       + "  methodImplId VARCHAR(255) NOT NULL,\n"
                       + "  bMechPid     VARCHAR(255) NOT NULL,\n"
                       + "  methodId     VARCHAR(255) NOT NULL\n"
                       + ")");
        st.executeUpdate("CREATE INDEX riMethodImpl_bMechPid ON riMethodImpl(bMechPid)");
        st.executeUpdate("CREATE INDEX riMethodImpl_methodId ON riMethodImpl(methodId)");

        st.executeUpdate("CREATE TABLE riMethodImplBinding (\n"
                       + "  methodImplBindingId INT NOT NULL GENERATED ALWAYS AS IDENTITY,\n"
                       + "  methodImplId        VARCHAR(255) NOT NULL,\n"
                       + "  dsBindKey           VARCHAR(255) NOT NULL\n"
                       + ")");
        st.executeUpdate("CREATE INDEX riMethodImplBinding_methodImplId ON riMethodImplBinding(methodImplId)");
        st.executeUpdate("CREATE INDEX riMethodImplBinding_dsBindKey ON riMethodImplBinding(dsBindKey)");

        st.executeUpdate("CREATE TABLE riMethodPermutation (\n"
                       + "  permutationId INT NOT NULL GENERATED ALWAYS AS IDENTITY,\n"
                       + "  methodId      VARCHAR(255) NOT NULL,\n"
                       + "  permutation   VARCHAR(255) NOT NULL\n"
                       + ")");
        st.executeUpdate("CREATE INDEX riMethodPermutation_methodId ON riMethodPermutation(methodId)");

        st.executeUpdate("CREATE TABLE riMethodMimeType (\n"
                       + "  mimeTypeId   INT NOT NULL GENERATED ALWAYS AS IDENTITY,\n"
                       + "  methodImplId VARCHAR(255) NOT NULL,\n"
                       + "  mimeType     VARCHAR(255) NOT NULL\n"
                       + ")");
        st.executeUpdate("CREATE INDEX riMethodMimeType_methodImplId ON riMethodMimeType(methodImplId)");

        st.close();
        _dbPool.free(conn);

    }

    protected void logDBState() throws Exception {
        StringBuffer out = new StringBuffer();
        out.append("CURRENT TABLE STATE\n\n");
        addTableStateInfo("riMethod", false, out);
        addTableStateInfo("riMethodImpl", false, out);
        addTableStateInfo("riMethodImplBinding", true, out);
        addTableStateInfo("riMethodPermutation", true, out);
        addTableStateInfo("riMethodMimeType", true, out);
        LOG.warn(out.toString());
    }

    private void addTableStateInfo(String table, boolean firstInt, StringBuffer out) throws Exception {
        out.append(table);
        out.append("\n---------------------\n");
        Connection conn = _dbPool.getConnection();
        Statement st = conn.createStatement();
        ResultSet r = st.executeQuery("SELECT * FROM " + table);
        int cols = r.getMetaData().getColumnCount();
        while (r.next()) {
            for (int i = 0; i < cols; i++) {
                if (i == 0 && firstInt) {
                    out.append(r.getInt(i+1));
                } else {
                    out.append("\t" + r.getString(i+1));
                }
            }
        }
        out.append("\n\n");
        r.close();
        st.close();
        _dbPool.free(conn);
    }

    /**
     * Initialize the RI at the given level and return it.
     *
     * If the RI is already initialized, it will be closed and re-initialized
     * at the given level.
     */
    protected void initRI(int indexLevel) throws Exception {
        if (_ri != null) {
            try { _ri.close(); } catch (Exception e) { }
        }
        MethodInfoStore methodInfoStore = 
                new DatabaseMethodInfoStore(_dbPool, indexLevel == 2);
        TripleGenerator generator =
                new MethodAwareTripleGenerator(methodInfoStore);
        
        _ri = new ResourceIndexImpl(getConnector(),
                                       methodInfoStore,
                                       generator,
                                       indexLevel,
                                       false);
    }

    /**
     * Get the TriplestoreConnector to be used in conjunction
     * with the ResourceIndexImpl.
     *
     * @throws Exception if constructing the connector fails for any reason.
     */
    private static TriplestoreConnector getConnector() throws Exception {

        HashMap config = new HashMap();

        config.put("backslashIsEscape",       "false");
        config.put("ddlGenerator",            "org.nsdl.mptstore.impl.derby.DerbyDDLGenerator");
        config.put("autoFlushBufferSize",     "1000");
        config.put("autoFlushDormantSeconds", "5");
        config.put("bufferFlushBatchSize",    "1000");
        config.put("bufferSafeCapacity",      "1000");
        config.put("fetchSize",               "1000");
        config.put("jdbcDriver",              DB_DRIVER);
        config.put("jdbcURL",                 DB_URL);
        config.put("username",                DB_USERNAME);
        config.put("password",                DB_PASSWORD);
        config.put("poolInitialSize",         "5");
        config.put("poolMaxSize",             "10");

        return TriplestoreConnector.init("org.trippi.impl.mpt.MPTConnector",
                                         config);
    }

    // Test tearDown

    @After
    public void tearDownTest() throws Exception {
        if (_ri != null) tearDownTriplestore();
    }

    /**
     * Clean up so the next test can run with fresh data.
     *
     * @throws Exception if tearDown fails for any reason.
     */
    @AfterClass
    public static void tearDownClass() throws Exception {
        if (_dbPool != null) tearDownDB();
    }

    private void tearDownTriplestore() throws Exception {

        // delete all triples from the RI
        File dump = new File(TEST_DIR + "/all-triples.txt");
        FileOutputStream out = null;
        try {
            // write all to temp file
            TripleIterator triples = _ri.findTriples(null, null, null, -1);
            out = new FileOutputStream(dump);
            triples.toStream(out, RDFFormat.TURTLE);
            try { out.close(); } catch (Exception e) { }
            out = null;

            // load all from temp file
            triples = TripleIterator.fromStream(new FileInputStream(dump), 
                                                RDFFormat.TURTLE);
            _ri.delete(triples, true);
        } finally {
            if (out != null) out.close();
            dump.delete();
        }

        _ri.close();
    }

    private static void tearDownDB() throws Exception {

        // destroy the Fedora-related RI tables
        Connection conn = _dbPool.getConnection();
        Statement st = conn.createStatement();
        st.executeUpdate("DROP TABLE riMethod");
        st.executeUpdate("DROP TABLE riMethodImpl");
        st.executeUpdate("DROP TABLE riMethodImplBinding");
        st.executeUpdate("DROP TABLE riMethodPermutation");
        st.executeUpdate("DROP TABLE riMethodMimeType");
        st.close();
        _dbPool.free(conn);
    }

    // do test methods

    protected void doAddDelTest(int riLevel, DigitalObject obj) 
            throws Exception {
        Set set = new HashSet();
        set.add(obj);
        doAddDelTest(riLevel, set);
    }

    protected void doAddDelTest(int riLevel,
                                Set objects)
            throws Exception {

        initRI(riLevel);

        addAll(objects, true);
        assertTrue("Did not get expected triples after add",
                   sameTriples(getExpectedTriples(riLevel, objects), 
                           getActualTriples(), true));

        deleteAll(objects, true);
        assertEquals("Some triples remained after delete",
                     0,
                     getActualTriples().size());
    }

    protected void doModifyTest(int riLevel,
                                DigitalObject origObject,
                                DigitalObject modifiedObject)
            throws Exception {
        Set origObjects = new HashSet();
        origObjects.add(origObject);
        doModifyTest(riLevel, origObjects, modifiedObject);
    }

    // if riLevel is -1, assume original objects have already been added
    // and we don't need to change the ri level
    protected void doModifyTest(int riLevel,
                                Set origObjects,
                                DigitalObject modifiedObject)
            throws Exception {

        if (riLevel > -1) {
            initRI(riLevel);
            addAll(origObjects, true);
        }

        DigitalObject origObject = null;

        // get a set with the modified object in place of its old version
        Set newObjects = new HashSet();
        for (DigitalObject orig : origObjects) {
            if (orig.getPid().equals(modifiedObject.getPid())) {
                origObject = orig;
            } else {
                newObjects.add(orig);
            }
        }
        newObjects.add(modifiedObject);

        modify(origObject, modifiedObject, true);

        assertTrue("Did not get expected triples after modify",
                   sameTriples(getExpectedTriples(riLevel, newObjects),
                           getActualTriples(), true));
    }

    // Utility methods for tests

    /**
     * Make a deep copy of the given digital object.
     */
    protected DigitalObject deepCopy(DigitalObject obj) throws Exception {

        // make sure DOTranslationUtility doesn't die
        if (System.getProperty("fedoraServerHost") == null
                || System.getProperty("fedoraServerPort") == null) {
            System.setProperty("fedoraServerHost", "localhost");
            System.setProperty("fedoraServerPort", "8080");
        }

        Map nsMap = new HashMap();
        nsMap.put(FOXMLDOSerializer.XSI_NS, "xsi");
        obj.setNamespaceMapping(nsMap);
        String charEncoding = "UTF-8";
        int transContext = DOTranslationUtility.SERIALIZE_STORAGE_INTERNAL;

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        FOXMLDOSerializer ser = new FOXMLDOSerializer();
        ser.serialize(obj, out, charEncoding, transContext);

        FOXMLDODeserializer deser = new FOXMLDODeserializer(charEncoding);
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        DigitalObject objCopy = new BasicDigitalObject();
        deser.deserialize(in, objCopy, charEncoding, transContext);

        // make sure dates of any to-be-added new components differ
        try { Thread.sleep(100); } catch (Exception e) { }

        return objCopy;
    }

    protected void modify(DigitalObject origObject, 
                          DigitalObject modifiedObject,
                          boolean flush) throws Exception {
        if (origObject.getFedoraObjectType() ==
                    DigitalObject.FEDORA_BDEF_OBJECT) {
            _ri.modifyBDefObject(getBDefReader(origObject),
                                 getBDefReader(modifiedObject));
        } else if (origObject.getFedoraObjectType() ==
                    DigitalObject.FEDORA_BMECH_OBJECT) {
            _ri.modifyBMechObject(getBMechReader(origObject),
                                  getBMechReader(modifiedObject));
        } else {
            _ri.modifyDataObject(getDOReader(origObject),
                                 getDOReader(modifiedObject));
        }
        if (flush) _ri.flushBuffer();
    }

    protected BDefReader getBDefReader(DigitalObject obj) throws Exception {
        return new SimpleBDefReader(null, null, null, null, null, obj);
    }

    protected BMechReader getBMechReader(DigitalObject obj) throws Exception {
        return new SimpleBMechReader(null, null, null, null, null, obj);
    }

    protected DOReader getDOReader(DigitalObject obj) throws Exception {
        return new SimpleDOReader(null, null, null, null, null, obj);
    }

    protected void addObj(DigitalObject obj, boolean flush)
            throws Exception {
        Set set = new HashSet();
        set.add(obj);
        addAll(set, flush);
    }

    protected void addAll(Set objects,
                          boolean flush)
            throws Exception {
        addOrDelAll(objects, flush, true);
    }

    protected void deleteAll(Set objects,
                             boolean flush)
            throws Exception {
        addOrDelAll(objects, flush, false);
    }

    private void addOrDelAll(Set objects,
            boolean flush, boolean add) throws Exception {
        for (DigitalObject obj : objects) {
            if (add) {
                if (obj.getFedoraObjectType() == 
                        DigitalObject.FEDORA_BDEF_OBJECT) {
                    _ri.addBDefObject(getBDefReader(obj));
                    _ri.flushBuffer();
                }
            } else {
                if (obj.getFedoraObjectType() == 
                        DigitalObject.FEDORA_OBJECT) {
                    _ri.deleteDataObject(getDOReader(obj));
                }
            }
        }
        for (DigitalObject obj : objects) {
            if (obj.getFedoraObjectType() == 
                    DigitalObject.FEDORA_BMECH_OBJECT) {
                if (add) {
                    _ri.addBMechObject(getBMechReader(obj));
                    _ri.flushBuffer();
                } else {
                    _ri.deleteBMechObject(getBMechReader(obj));
                    _ri.flushBuffer();
                }
            }
        }
        for (DigitalObject obj : objects) {
            if (add) {
                if (obj.getFedoraObjectType() == 
                        DigitalObject.FEDORA_OBJECT) {
                    _ri.addDataObject(getDOReader(obj));
                }
            } else {
                if (obj.getFedoraObjectType() == 
                        DigitalObject.FEDORA_BDEF_OBJECT) {
                    _ri.deleteBDefObject(getBDefReader(obj));
                    _ri.flushBuffer();
                }
            }
        }
        if (flush) _ri.flushBuffer();
    }

    protected Set getExpectedTriples(int riLevel,
                                             Set objects)
            throws Exception {

        // we can return early in this case
        if (riLevel == 0) {
            return new HashSet();
        }
        
        // add all to a mock repository reader
        MockRepositoryReader repo = new MockRepositoryReader();
        for (DigitalObject obj : objects) {
            repo.putObject(obj);
        }

        // prepare appropriate MethodInfoStore and TripleGenerator
        MethodInfoStore methodInfo = new MockMethodInfoStore(riLevel == 2);
        TripleGenerator generator = new MethodAwareTripleGenerator(methodInfo);

        Set expected = new HashSet();

        // get triples for all bdefs
        for (DigitalObject obj : objects) {
            if (obj.getFedoraObjectType() == 
                    DigitalObject.FEDORA_BDEF_OBJECT) {
                BDefReader reader = repo.getBDefReader(false, null, 
                        obj.getPid());
                methodInfo.putBDefInfo(reader);
                expected.addAll(generator.getTriplesForBDef(reader));
            }
        }

        // get triples for all bmechs
        for (DigitalObject obj : objects) {
            if (obj.getFedoraObjectType() == 
                    DigitalObject.FEDORA_BMECH_OBJECT) {
                BMechReader reader = repo.getBMechReader(false, null, 
                        obj.getPid());
                methodInfo.putBMechInfo(reader);
                expected.addAll(generator.getTriplesForBMech(reader));
            }
        }

        // get triples for all data objects
        for (DigitalObject obj : objects) {
            if (obj.getFedoraObjectType() == DigitalObject.FEDORA_OBJECT) {
                DOReader reader = repo.getReader(false, null, obj.getPid());
                expected.addAll(generator.getTriplesForDataObject(reader));
            }
        }

        return expected;

    }

    protected boolean sameTriples(Set expected,
                                  Set actual,
                                  boolean logDiffs) {
        TreeSet eStrings = new TreeSet();
        for (Triple triple : expected) {
            eStrings.add(RDFUtil.toString(triple));
        }

        TreeSet aStrings = new TreeSet();
        for (Triple triple : actual) {
            aStrings.add(RDFUtil.toString(triple));
        }

        if (eStrings.equals(aStrings)) {
            return true;
        } else {
            if (logDiffs) {
                StringBuffer out = new StringBuffer();
                out.append("Triple sets differ.\n");
                out.append("Expected set has " + expected.size() + " triples.\n");
                out.append("Actual set has " + actual.size() + " triples.\n\n");
                out.append("Expected triples:\n");
                for (String t : eStrings) {
                    out.append("  " + t + "\n");
                }
                out.append("\nActual triples:\n");
                for (String t : aStrings) {
                    out.append("  " + t + "\n");
                }
                LOG.warn(out.toString());
            }
            return false;
        }

    }

    protected Set getActualTriples()
            throws Exception {
        return getActualTriples(null, null, null);
    }

    protected Set getActualTriples(SubjectNode subject,
                                           PredicateNode predicate,
                                           ObjectNode object)
            throws Exception {
        Set set = new HashSet();
        TripleIterator iter = _ri.findTriples(subject, predicate, object, -1);
        while (iter.hasNext()) {
            set.add(iter.next());
        }
        iter.close();
        return set;
    }

    /**
     * Get the DC xml for an object.
     */
    protected String getDC(String content) {
        StringBuffer x = new StringBuffer();
        x.append("\n");
        x.append(content + "\n");
        x.append("");
        return x.toString();
    }

    /**
     * Get the RELS-EXT xml for an object.
     */
    protected String getRELSEXT(String content) {
        StringBuffer x = new StringBuffer();
        x.append("\n");
        x.append("\n");
        x.append(content + "\n");
        x.append("\n");
        x.append("");
        return x.toString();
    }

    /**
     * Get the METHODMAP xml for a bDef.
     */
    protected static String getMethodMap(Set methodDefs) {
        return getMethodMap(methodDefs, null, false);
    }

    /**
     * Get the METHODMAP xml for a bDef or bMech.
     */
    protected static String getMethodMap(Set methodDefs,
                                         Map> inputKeys,
                                         boolean forBMech) {
        StringBuffer xml = new StringBuffer();
        xml.append("\n");
        for (ParamDomainMap methodDef : methodDefs) {
            String method = methodDef.getMethodName();
            xml.append("  \n");
            for (String paramName : methodDef.keySet()) {
                ParamDomain domain = methodDef.get(paramName);
                xml.append("    \n");
                if (domain.size() > 0) {
                    xml.append("      \n");
                    for (String value : domain) {
                        xml.append("        \n");
                    }
                    xml.append("      \n");
                }
                xml.append("    \n");
            }
            if (forBMech) {
                Set keys = inputKeys.get(method);
                if (keys != null) {
                    for (String key : keys) {
                        xml.append("    \n");
                    }
                }

                xml.append("    \n");
            }
            xml.append("  \n");
        }
        xml.append("");
        return xml.toString();
    }

    /**
     * Get the DSINPUTSPEC xml for a BMech.
     */
    protected static String getInputSpec(String bDefPID,
                                         Map> inputTypes) {
        StringBuffer xml = new StringBuffer();
        xml.append("\n");
        for (String key : inputTypes.keySet()) {
            xml.append("  \n");
            xml.append("    label\n");
            for (String mimeType : inputTypes.get(key)) {
                xml.append("    " + mimeType + "\n");
            }
            xml.append("    inst\n");
            xml.append("  \n");
        }
        xml.append("\n");
        return xml.toString();
    }

    private static void addXSDType(String name, StringBuffer xml) {
        xml.append("      \n");
        xml.append("        \n");
        xml.append("      \n");
    }

    /**
     * Get the WSDL xml for a BMech.
     */
    protected static String getWSDL(Set methodDefs,
                                    Map> inputKeys,
                                    Map> outputTypes) {
        StringBuffer xml = new StringBuffer();

        xml.append("\n");

        //
        // xsd type definitions
        //

        xml.append("  \n");
        xml.append("    \n");
        Set addedTypes = new HashSet();
        for (ParamDomainMap methodDef : methodDefs) {
            // one type def per distinct user param name
            for (String name : methodDef.keySet()) {
                if (addedTypes.add(name + "Type")) {
                    addXSDType(name + "Type", xml);
                }
            }

            // one type def per distinct ds input key
            for (String key : inputKeys.get(methodDef.getMethodName())) {
                if (addedTypes.add(key + "Type")) {
                    addXSDType(key + "Type", xml);
                }
            }
        }
        xml.append("    \n");
        xml.append("  \n");

        //
        // message definitions
        //

        // one request message per method
        for (ParamDomainMap methodDef : methodDefs) {
            String method = methodDef.getMethodName();
            xml.append("  \n");
            // one part per user param
            for (String name : methodDef.keySet()) {
                xml.append("    \n");
            }
            // one part per ds input key
            for (String key : inputKeys.get(method)) {
                xml.append("    \n");
            }
            xml.append("  \n");
        }
        // one dissemResponse output message
        xml.append("  \n");
        xml.append("    \n");
        xml.append("  \n");

        //
        // port type (per-method input/output messages)
        //
        xml.append("  \n");
        for (ParamDomainMap methodDef : methodDefs) {
            String method = methodDef.getMethodName();
            xml.append("    \n");
            xml.append("      \n");
            xml.append("      \n");
            xml.append("    \n");
        }
        xml.append("  \n");

        //
        // service location
        // 
        xml.append("  \n");
        xml.append("    \n");
        xml.append("      \n");
        xml.append("    \n");
        xml.append("  \n");

        //
        // operation locations and input/output bindings
        //
        xml.append("  \n");
        xml.append("    \n");
        for (ParamDomainMap methodDef : methodDefs) {
            String method = methodDef.getMethodName();
            xml.append("    \n");

            // location = ..?userParm1=(userParm1)&key1=KEY1..etc
            StringBuffer location = new StringBuffer();
            location.append(method + "?");
            boolean first = true;
            for (String name : methodDef.keySet()) {
                if (!first) {
                    location.append("&");
                }
                location.append(name + "=(" + name + ")");
                first = false;
            }
            for (String key : inputKeys.get(method)) {
                if (!first) {
                    location.append("&");
                }
                location.append(key.toLowerCase() + "=(" + key + ")");
                first = false;
            }
            xml.append("      \n");

            // input is always urlReplacement
            xml.append("      \n");

            // output lists all possible output mime types
            xml.append("      \n");
            for (String mimeType : outputTypes.get(method)) {
                xml.append("        \n");
            }
            xml.append("      \n");

            xml.append("    \n");
        }
        xml.append("  \n");

        xml.append("\n");
        return xml.toString();
    }

    protected static Set getTestObjects(int num,
                                                       int datastreamsPerObject) {
        Set set = new HashSet(num);
        for (int i = 0; i < num; i++) {
            DigitalObject obj = getTestObject("test:" + i, "label" + i);
            for (int j = 0; j < datastreamsPerObject; j++) {
                addEDatastream(obj, "DS" + j);
            }
            set.add(obj);
        }
        return set;
    }

    protected TripleIterator spo(String query) throws Exception {
        return _ri.findTriples("spo", query, -1, false);
    }

    protected static void addDisseminator(DigitalObject obj, String id,
            String bDefPID, String bMechPID, Map bindings) {
        List dissems = obj.disseminators(id);
        Disseminator diss = new Disseminator();
        diss.bDefID = bDefPID;
        diss.bMechID = bMechPID;
        diss.dissCreateDT = new Date();
        diss.dissID = id;
        diss.dissLabel = "disseminator";
        diss.dissState = "A";
        diss.dissVersionID = id + "." + dissems.size();
        DSBindingMap bindMap = new DSBindingMap();
        bindMap.dsBindMapLabel = "bindmap";
        bindMap.dsBindMechanismPID = bMechPID;
        DSBinding[] dsBindings = new DSBinding[bindings.size()];
        int i = 0;
        for (String key : bindings.keySet()) {
            String dsID = bindings.get(key);
            dsBindings[i] = new DSBinding();
            dsBindings[i].bindKeyName = key;
            dsBindings[i].bindLabel = "bindlabel";
            dsBindings[i].datastreamID = dsID;
            dsBindings[i].seqNo = "1";
            i++;
        }
        bindMap.dsBindings = dsBindings;
        diss.dsBindMap = bindMap; 
        dissems.add(diss);
    }

    protected static void addEDatastream(DigitalObject obj, String id) {
        DatastreamReferencedContent ds = new DatastreamReferencedContent();
        ds.DSControlGrp = "E";
        ds.DSMIME = "text/plain";
        ds.DSLocation = "http://www.example.org/e.txt";
        ds.DSLocationType = "URL";
        ds.DSSize = 1;
        addDatastream(obj, id, ds);
    }

    protected static void addRDatastream(DigitalObject obj, String id) {
        DatastreamReferencedContent ds = new DatastreamReferencedContent();
        ds.DSControlGrp = "R";
        ds.DSMIME = "text/plain";
        ds.DSLocation = "http://www.example.org/r.txt";
        ds.DSLocationType = "URL";
        ds.DSSize = 2;
        addDatastream(obj, id, ds);
    }

    protected static void addXDatastream(DigitalObject obj, String id, String xml) {
        DatastreamXMLMetadata ds = new DatastreamXMLMetadata();
        ds.DSControlGrp = "X";
        ds.DSMIME = "text/xml";
        ds.DSSize = xml.length();
        try { ds.xmlContent = xml.getBytes("UTF-8"); } catch (Exception e) { }
        addDatastream(obj, id, ds);
    }

    protected static void addMDatastream(DigitalObject obj, String id) {
        DatastreamManagedContent ds = new DatastreamManagedContent();
        ds.DSControlGrp = "M";
        ds.DSMIME = "image/jpeg";
        ds.DSLocation = "bogusLocation";
        ds.DSLocationType = "INTERNAL";
        ds.DSSize = 4;
        addDatastream(obj, id, ds);
    }

    private static void addDatastream(DigitalObject obj, String id, Datastream ds) {
        List versions = obj.datastreams(id);
        ds.DatastreamID = id;
        ds.DSState = "A";
        ds.DSVersionable = true;
        ds.DSVersionID = id + "." + versions.size();
        ds.DSLabel = "ds label";
        ds.DSCreateDT = new Date();
        versions.add(ds);
    }

    protected static DigitalObject getTestObject(String pid,
                                                 String label) {
        Date now = new Date();
        return getTestObject(pid, DigitalObject.FEDORA_OBJECT, "A",
                "someOwnerId", label, "someContentModelId",
                now, now);
    }

    protected static DigitalObject getTestBDef(String pid,
                                               String label,
                                               Set methodDefs) {
        Date now = new Date();
        DigitalObject obj = getTestObject(pid, 
                DigitalObject.FEDORA_BDEF_OBJECT, "A",
                "someOwnerId", label, "someContentModelId", now, now);
        addXDatastream(obj, "METHODMAP", getMethodMap(methodDefs));
        return obj;
    }

    protected static DigitalObject getTestBMech(String pid, 
            String label,
            String bDefPID, 
            Set methodDefs,
            Map> inputKeys, 
            Map> inputTypes,
            Map> outputTypes) {

        Date now = new Date();
        DigitalObject obj = getTestObject(pid, 
                DigitalObject.FEDORA_BMECH_OBJECT, "A",
                "someOwnerId", label, "someContentModelId", now, now);

        String methodMapXML = getMethodMap(methodDefs, inputKeys, true);
        addXDatastream(obj, "METHODMAP", methodMapXML);

        String inputSpecXML = getInputSpec(bDefPID, inputTypes);
        addXDatastream(obj, "DSINPUTSPEC", inputSpecXML);

        String wsdlXML = getWSDL(methodDefs, inputKeys, outputTypes);
        addXDatastream(obj, "WSDL", wsdlXML);

        return obj;
    }

    protected static DigitalObject getTestObject(String pid,
                                                 int fedoraObjectType,
                                                 String state,
                                                 String ownerId,
                                                 String label,
                                                 String contentModelId,
                                                 Date createDate,
                                                 Date lastModDate) {
        DigitalObject obj = new BasicDigitalObject();
        obj.setPid(pid);
        obj.setFedoraObjectType(fedoraObjectType);
        obj.setState(state);
        obj.setOwnerId(ownerId);
        obj.setLabel(label);
        obj.setContentModelId(contentModelId);
        obj.setCreateDate(createDate);
        obj.setLastModDate(lastModDate);
        return obj;
    }

    // bdef:1 has one no-parameter method
    protected static DigitalObject getBDefOne() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        methodDefs.add(methodOne);
        return getTestBDef("test:bdef1", "bdef1", methodDefs);
    }

    // bdef:1b has two no-parameter methods
    protected static DigitalObject getBDefOneB() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        methodDefs.add(methodOne);
        ParamDomainMap methodTwo = new ParamDomainMap("methodTwo");
        methodDefs.add(methodTwo);
        return getTestBDef("test:bdef1b", "bdef1b", methodDefs);
    }


    // bdef:1c has one no-parameter method (same as bdef:1)
    protected static DigitalObject getBDefOneC() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        methodDefs.add(methodOne);
        return getTestBDef("test:bdef1c", "bdef1c", methodDefs);
    }

    // bdef:2 has one required one-parameter method with two possible values
    protected static DigitalObject getBDefTwo() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", true);
        argOneDomain.add("val1");
        argOneDomain.add("val2");
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);
        return getTestBDef("test:bdef2", "bdef2", methodDefs);
    }

    // bdef:2b has two required one-parameter methods with two possible values
    protected static DigitalObject getBDefTwoB() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", true);
        argOneDomain.add("val1");
        argOneDomain.add("val2");
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);
        ParamDomainMap methodTwo = new ParamDomainMap("methodTwo");
        methodTwo.put("argOne", argOneDomain);
        methodDefs.add(methodTwo);
        return getTestBDef("test:bdef2b", "bdef2b", methodDefs);
    }

    // bdef:3 has one optional one-parameter method with any possible value
    protected static DigitalObject getBDefThree() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", false);
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);
        return getTestBDef("test:bdef3", "bdef3", methodDefs);
    }

    // bdef:3b has two optional one-parameter methods with any possible value
    protected static DigitalObject getBDefThreeB() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", false);
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);
        ParamDomainMap methodTwo = new ParamDomainMap("methodTwo");
        methodTwo.put("argOne", argOneDomain);
        methodDefs.add(methodTwo);
        return getTestBDef("test:bdef3b", "bdef3b", methodDefs);
    }

    // bdef:4 has two one-parameter methods, one required with two possible 
    //        values and the other optional with any possible value
    protected static DigitalObject getBDefFour() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", true);
        argOneDomain.add("val1");
        argOneDomain.add("val2");
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);
        ParamDomainMap methodTwo = new ParamDomainMap("methodTwo");
        argOneDomain = new ParamDomain("argOne", false);
        methodTwo.put("argOne", argOneDomain);
        methodDefs.add(methodTwo);
        return getTestBDef("test:bdef4", "bdef4", methodDefs);
    }

    // construct a map representing key-to-ds bindings with 1 or 2 keys
    protected static Map> getMap(String key1,
                                                   String[] values1,
                                                   String key2,
                                                   String[] values2) {
        Set valueSet1 = new HashSet();
        for (String value : values1) {
            valueSet1.add(value);
        }
        Map> map = new HashMap>();
        map.put(key1, valueSet1);
        if (key2 != null) {
            Set valueSet2 = new HashSet();
            for (String value : values2) {
                valueSet2.add(value);
            }
            map.put(key2, valueSet2);
        }
        return map;
    }

    // bmech:1 implements bdef:1 and takes one datastream
    protected static DigitalObject getBMechOne() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        methodDefs.add(methodOne);

        return getTestBMech("test:bmech1", "bmech1", "test:bdef1", 
                methodDefs, 
                getMap("methodOne", new String[] {"KEY1"}, null, null),
                getMap("KEY1", new String[] {"text/xml"}, null, null),
                getMap("methodOne", new String[] {"text/xml"}, null, null));
    }

    // bmech:1b implements bdef:1b and takes one datastream
    protected static DigitalObject getBMechOneB() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        methodDefs.add(methodOne);
        ParamDomainMap methodTwo = new ParamDomainMap("methodTwo");
        methodDefs.add(methodTwo);

        return getTestBMech("test:bmech1b", "bmech1b", "test:bdef1b", 
                methodDefs, 
                getMap("methodOne", new String[] {"KEY1"}, 
                       "methodTwo", new String[] {"KEY2"}),
                getMap("KEY1", new String[] {"text/xml"}, 
                       "KEY2", new String[] {"text/xml"}),
                getMap("methodOne", new String[] {"text/xml"},
                       "methodTwo", new String[] {"text/xml"}));
    }

    // bmech:1c implements bdef:1c and takes one datastream
    protected static DigitalObject getBMechOneC() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        methodDefs.add(methodOne);

        return getTestBMech("test:bmech1c", "bmech1c", "test:bdef1c", 
                methodDefs, 
                getMap("methodOne", new String[] {"KEY1"}, null, null),
                getMap("KEY1", new String[] {"text/xml"}, null, null),
                getMap("methodOne", new String[] {"text/xml"}, null, null));
    }

    // bmech:1d implements bdef:1 and takes TWO datastreams
    protected static DigitalObject getBMechOneD() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        methodDefs.add(methodOne);

        return getTestBMech("test:bmech1d", "bmech1d", "test:bdef1", 
                methodDefs, 
                getMap("methodOne", new String[] {"KEY1", "KEY2"}, null, null),
                getMap("KEY1", new String[] {"text/xml"}, "KEY2", new String[] {"text/xml"}),
                getMap("methodOne", new String[] {"text/xml"}, null, null));
    }

    // bmech:2 implements bdef:2 and takes one datastream
    protected static DigitalObject getBMechTwo() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", true);
        argOneDomain.add("val1");
        argOneDomain.add("val2");
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);

        return getTestBMech("test:bmech2", "bmech2", "test:bdef2", 
                methodDefs, 
                getMap("methodOne", new String[] {"KEY1"}, null, null),
                getMap("KEY1", new String[] {"text/xml"}, null, null),
                getMap("methodOne", new String[] {"text/xml"}, null, null));
    }

    // bmech:2b implements bdef:2b and takes one datastream
    protected static DigitalObject getBMechTwoB() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", true);
        argOneDomain.add("val1");
        argOneDomain.add("val2");
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);
        ParamDomainMap methodTwo = new ParamDomainMap("methodTwo");
        methodTwo.put("argOne", argOneDomain);
        methodDefs.add(methodTwo);

        return getTestBMech("test:bmech2b", "bmech2b", "test:bdef2b", 
                methodDefs, 
                getMap("methodOne", new String[] {"KEY1"}, 
                       "methodTwo", new String[] {"KEY2"}),
                getMap("KEY1", new String[] {"text/xml"}, 
                       "KEY2", new String[] {"text/xml"}),
                getMap("methodOne", new String[] {"text/xml"},
                       "methodTwo", new String[] {"text/xml"}));
    }

    // bmech:3 implements bdef:3 and takes one datastream
    protected static DigitalObject getBMechThree() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", false);
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);

        return getTestBMech("test:bmech3", "bmech3", "test:bdef3", 
                methodDefs, 
                getMap("methodOne", new String[] {"KEY1"}, null, null),
                getMap("KEY1", new String[] {"text/xml"}, null, null),
                getMap("methodOne", new String[] {"text/xml"}, null, null));
    }

    // bmech:3b implements bdef:3b and takes one datastream
    protected static DigitalObject getBMechThreeB() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", false);
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);
        ParamDomainMap methodTwo = new ParamDomainMap("methodTwo");
        methodTwo.put("argOne", argOneDomain);
        methodDefs.add(methodTwo);

        return getTestBMech("test:bmech3b", "bmech3b", "test:bdef3b", 
                methodDefs, 
                getMap("methodOne", new String[] {"KEY1"}, 
                       "methodTwo", new String[] {"KEY2"}),
                getMap("KEY1", new String[] {"text/xml"}, 
                       "KEY2", new String[] {"text/xml"}),
                getMap("methodOne", new String[] {"text/xml"},
                       "methodTwo", new String[] {"text/xml"}));
    }

    // bmech:4 implements bdef:4 and takes one datastream
    protected static DigitalObject getBMechFour() {
        Set methodDefs = new HashSet();
        ParamDomainMap methodOne = new ParamDomainMap("methodOne");
        ParamDomain argOneDomain = new ParamDomain("argOne", true);
        argOneDomain.add("val1");
        argOneDomain.add("val2");
        methodOne.put("argOne", argOneDomain);
        methodDefs.add(methodOne);
        ParamDomainMap methodTwo = new ParamDomainMap("methodTwo");
        argOneDomain = new ParamDomain("argOne", false);
        methodTwo.put("argOne", argOneDomain);
        methodDefs.add(methodTwo);

        return getTestBMech("test:bmech4", "bmech4", "test:bdef4", 
                methodDefs, 
                getMap("methodOne", new String[] {"KEY1"}, 
                       "methodTwo", new String[] {"KEY2"}),
                getMap("KEY1", new String[] {"text/xml"}, 
                       "KEY2", new String[] {"text/xml"}),
                getMap("methodOne", new String[] {"text/xml"},
                       "methodTwo", new String[] {"text/xml"}));
    }

    // get an object named test:1 with one datastream (DS1) and one 
    // disseminator that has any number of keys (KEY1, etc) pointing to the ds.
    protected DigitalObject getObjectWithDissem(String bDefPID,
                                              String bMechPID,
                                              int numKeys) throws Exception {
        DigitalObject obj = getTestObject("test:1", "test");
        addEDatastream(obj, "DS1");
        addDisseminator(obj, "DISS1", bDefPID, bMechPID, getBindings(numKeys));
        return obj;
    }

    protected Map getBindings(int numKeys) {
        Map bindings = new HashMap();
        for (int i = 1; i <= numKeys; i++) {
            bindings.put("KEY" + i, "DS1");
        }
        return bindings;
    }

    // get a set containing three digital objects
    protected Set getObjectSet(DigitalObject o1,
                                              DigitalObject o2,
                                              DigitalObject o3) {
        Set set = new HashSet();
        set.add(o1);
        set.add(o2);
        set.add(o3);
        return set;
    }

    public void startFlushing(int sleepMS) throws Exception {
        if (_flusher != null) { 
            try {
                finishFlushing();
            } catch (Exception e) {
                System.err.println("Error stopping old flusher!!");
                e.printStackTrace();
            }
            throw new Exception("Flusher was already running!");
        }
        _flusher = new Flusher(_ri, sleepMS);
        _flusher.start();
    }

    // finish async flushing and do a final flush
    public void finishFlushing() throws Exception {
        _flusher.finish();
        _ri.flushBuffer();
        _flusher = null;
    }

    // Inner classes for tests

    /**
     * A Thread that continuously flushes the buffer.
     */
    public class Flusher extends Thread {

        private ResourceIndex _ri;
        private int _sleepMS;
        private boolean _shouldFinish = false;
        private Exception _error;

        /**
         * Construct a flusher that sleeps the given number of milliseconds
         * between flush attempts.
         *
         * @param sleepMS milliseconds to sleep.  Will simply yield between
         *                flush attempts if less than 1.
         */
        public Flusher(ResourceIndex ri, int sleepMS) {
            _ri = ri;
            _sleepMS = sleepMS;
        }

        /**
         * Set signal for flusher to finish and wait for it.
         *
         * @throws Exception if the flusher encountered an error any time 
         *                   while it was running.
         */
        public void finish() throws Exception {
            _shouldFinish = true;
            while (this.isAlive()) {
                try { Thread.sleep(50); } catch (InterruptedException e) { }
            }
            if (_error != null) {
                throw _error;
            }
        }

        /**
         * Flush the buffer until the finish signal arrives from another
         * thread.
         */
        public void run() {
            try {
                while (!_shouldFinish) {
                    if (_sleepMS > 0) {
                        try { Thread.sleep(_sleepMS); } catch (InterruptedException e) { }
                    } else {
                        Thread.yield();
                    }
                    _ri.flushBuffer();
                }
            } catch (Exception e) {
                _error = e;
            }
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy