CNRI Repository API Documentation

Version 1.0 October 31st 2013


Table of Contents

API Jar file

Making a connection to the repository

Secret key/password based authentication

Private key based authentication

Creating a Digital Object

Editing a Digital Object

Deleting a Digital Object

Storing a File in a Digital Object

Reading a File from a Digital Object

Searching the Repository

AttributeQuery

BooleanQuery

RawQuery

Nested Queries

ElementAttributeQuery

QueryParams


API Jar file

The API described in this document is contained in the dorepository-api-1.0.jar file. Add this file as well as do.jar to your project's build path.

Making a connection to the repository

In order to make a connection to the repository server you need an instance of NetworkedRepository. There are a number of different NetworkedRepository constructors available. They vary based on the method of authentication used. The simplest approach is to use secret key based authentication. This allows you to connect to a repository server without having to create a user handle in the Handle System, instead a username and password can be specified in the password.dct file.

Secret key/password based authentication

String repoHandle = "cnri.test/repo";

String host = "10.0.1.4";

int port = 9900;

byte[] pubKeyBytes = getPubKeyBytes("keys/testserver/publickey");

String userHandle = "cnri.test/admin";

byte[] userPassword = "password".getBytes();

Repository repository =

new NetworkedRepository(repoHandle, host, port, pubKeyBytes, userHandle, userPassword);

The repoHandle needs to match the value of the serviceid field in the server config.dct file.

The pubKeyBytes are the bytes from the publickey file in the server directory. This public key represents the identity of the repository and is used by the client to authenticate the server.

The userHandle and userPassword can be stored in the password.dct file in the server directory. An example password.dct file is shown here:

{

"cnri.test/admin"="password"

}

Alternatively userHandle can refer to a handle in the Handle System that contains an HS_SECKEY handle value. In which case the password must be the value of that HS_SECKEY.

Private key based authentication

Authentication can also be carried out using the public/private key pair of a Handle System user. The public key of the user needs to be stored in an HS_PUBKEY handle value in the Handle System.

String repoHandle = "cnri.test/repo";

String host = "10.0.1.4";

int port = 9900;

byte[] pubKeyBytes = getPubKeyBytes("keys/testserver/publickey");

String userHandle = "cnri.test/admin";

String privateKeyFilePath = "keys/adminPrivateKey";

String passphrase = "passphrase";

repository = NetworkedRepository(repoHandle, host, port, pubKeyBytes, userHandle,

privateKeyFilePath, passphrase);

Supply the path to the locally stored private key. The private key can optionally be encrypted with a passphrase. If the private key is not encrypted the passphrase can be null.

For other ways of instantiating a NetworkedRepository please see the java doc.

Creating a Digital Object

DigitalObject object1 = new repository.createDigitalObject("userDefinedObjectId");

Alternatively you can pass null as the id of the Digital Object to be assigned the next available id.

DigitalObject object1 = new repository.createDigitalObject(null);

Editing a Digital Object

A Digital Object contains a map of attributes where the key and value are Strings. Attributes are written with the setAttribute method and read with the getAttribute method.

object1.setAttribute("attributeName", "attributeValue");

String value = object1.getAttribute("attributeName");

Each call to setAttribute writes directly through to the remote server. It is sometimes desirable to write a set of attributes as a single atomic operation. This can be done by creating a Map<String, String>, setting the desired values on the map and then passing it to the setAttributes method.

Map<String, String> atts = new HashMap<String, String>();

stts.put("attName1", "attValue1");

stts.put("attName2", "attValue2");

stts.put("attName3", "attValue3");

object1.setAttributes(atts);

All the attributes of an object can also be retrieved in a single operation with getAttributes.

Map<String, String> atts = object1.getAttributes();

Deleting a Digital Object

You can either call the delete method on an instance of the Digital Object or you can call the delete method on the instance of Repository passing in the id of the object.

object1.delete();

repository.deleteDigitalObject("object1");

Storing Data in a Digital Object

In addition to attributes a Digital Object can also hold multiple data elements. A data element contains an arbitrary list of bytes and has methods for reading and writing to it.

DataElement element = object1.createDataElement("elementName");

To write to a data element call its write method passing in an InputStream.

FileInputStream fileIn = new FileInputStream(new File("/Users/test/documentation.pdf"));

element.write(fileIn);

In the above example a local file is accessed with a FileInputStream and written to a Digital Objects data element. Note that the DataElement.write() method takes any InputStream.

Each data element has its own set of attributes that can be accessed in a similar way to the attributes on a DigitalObject.

element.setAttribute("attributeName", "attributeValue");

Reading Data from a Digital Object

Calling the read method on a DataElement returns an InputStream which can be read from in the usual way.

InputStream in = element.read();

Searching the Repository

Objects stored in a repository are indexed and searchable. It is possible to query the repository using the lucene query syntax and while some more advanced search operations are available with the lucene query syntax the prefered method is to construct a Query object.

DigitalObject mercury = repository.createDigitalObject("mercury");

mercury.setAttribute("name", "mercury");

mercury.setAttribute("temp", "900");

mercury.setAttribute("haswater", "false");

mercury.setAttribute("hasLife", "false");

mercury.setAttribute("tooHot", "true");

mercury.setAttribute("tooCold", "false");

DigitalObject venus = repository.createDigitalObject("venus");

venus.setAttribute("name", "venus");

venus.setAttribute("temp", "400");

venus.setAttribute("haswater", "false");

venus.setAttribute("hasAtmos", "true");

venus.setAttribute("hasLife", "false");

venus.setAttribute("tooHot", "true");

venus.setAttribute("tooCold", "false");

           

DigitalObject earth = repository.createDigitalObject("earth");

earth.setAttribute("name", "earth");

earth.setAttribute("temp", "40");

earth.setAttribute("haswater", "true");

earth.setAttribute("hasAtmos", "true");

earth.setAttribute("hasLife", "true");

earth.setAttribute("tooHot", "false");

earth.setAttribute("tooCold", "false");

           

DigitalObject mars = repository.createDigitalObject("mars");

mars.setAttribute("name", "mars");

mars.setAttribute("temp", "-60");

mars.setAttribute("haswater", "true");

mars.setAttribute("hasAtmos", "true");

mars.setAttribute("hasLife", "false");

mars.setAttribute("tooHot", "false");

mars.setAttribute("tooCold", "true");

AttributeQuery

The most basic query is the AttributeQuery. Searching a repository with an attribute query will return an iterator over Digital Objects that have the specified attribute with the specified value.

Query hasWater = new AttributeQuery("haswater", "false")

CloseableIterator<DigitalObject> resultsIter = repository.search(hasWater);

while(resultsIter.hasNext()) {

DigitalObject dobj = resultsIter.next();

           System.out.println(dobj.getHandle());

}

resultsIter.close();

In this example the search will return the DigitalObjects mercury and venus.

BooleanQuery

A BooleanQuery is a way of combining multiple queries together along with BooleanClauses.

AttributeQuery hasWater = new AttributeQuery("haswater", "true");

AttributeQuery hasAtmos = new AttributeQuery("hasAtmos", "true");

AttributeQuery tooHot = new AttributeQuery("tooHot", "true");

AttributeQuery tooCold = new AttributeQuery("tooCold", "true");

           

List<BooleanClause> conditionsForLife = new ArrayList<BooleanClause>();

conditionsForLife.add(new BooleanClause(hasWater, BooleanClause.Occur.MUST));

conditionsForLife.add(new BooleanClause(hasAtmos, BooleanClause.Occur.MUST));

conditionsForLife.add(new BooleanClause(tooHot, BooleanClause.Occur.MUST_NOT));

conditionsForLife.add(new BooleanClause(tooCold, BooleanClause.Occur.MUST_NOT));

BooleanQuery conditionsForLifeQ = new BooleanQuery(conditionsForLife);

CloseableIterator<DigitalObject> resultsIter = repository.search(conditionsForLifeQ);

In this example we create four AttributeQueries. Each AttributeQuery is wrapped in a BooleanClause which is used to indicate if the query MUST, SHOULD or MUST_NOT occur in the results. This is modeled on the programmatic API for Lucine where a BooleanQuery will match an object if and only if it matches every MUST subquery; it matches at least one SHOULD subquery (or there is no such subquery); and it matches no MUST_NOT subquery.

RawQuery

A RawQuery allows you to create a Query object using the Lucene query syntax. For example the same conditions for life query shown above could be expressed as a RawQuery like this:

String queryString =

"objatt_haswater:true AND objatt_hasAtmos:true NOT objatt_tooHot:true NOT objatt_tooCold:true"

Query rawConditionsForLifeQ = new RawQuery(queryString);

CloseableIterator<DigitalObject> resultsIter = repository.search(rawConditionsForLifeQ);

ElementAttributeQuery

The ElementAttributeQuery is similar to an AttributeQuery but searches the attributes on DataElements rather than the attributes on the DigitalObjects.

Query q = new ElementAttributeQuery("elementName", "attributeName", "attributeValue");

CloseableIterator<DigitalObject> resultsIter = repository.search(q);

QueryParams

There exists an additional search method on Repository that takes a QueryParams object. The QueryParams object allows you to paginate results, restricting page size and specifying page number.

Query q = new AttributeQuery("attributeName", "attributeValue");

int pageNum = 3;

int pageSize = 10;

QueryParams queryParams = new QueryParams(pageNum, pageSize, null);

CloseableIterator<DigitalObject> resultsIter = repository.search(q, queryParams);

Where a pageNum of zero will return the first page.

The optional 3rd parameter in a QueryParams object is a List<String> of sort fields. Where each string is an attribute name the results should be sorted by.

Query q = new AttributeQuery("attributeName", "attributeValue");

int pageNum = 3;

int pageSize = 10;

List<String> sortFields = new ArrayList<String>();

sortFields.add("size");

sortFields.add("date");

QueryParams queryParams = new QueryParams(pageNum, pageSize, sortFields);

CloseableIterator<DigitalObject> resultsIter = repository.search(q, queryParams);