Skip to content

Commit

Permalink
Merge pull request #29 from futures/DublinCoreIndexer
Browse files Browse the repository at this point in the history
Create initial Dublin Core indexer framework and REST API endpoint.
  • Loading branch information
barmintor committed Feb 7, 2013
2 parents 245b8d7 + 96662a0 commit bae91c7
Show file tree
Hide file tree
Showing 14 changed files with 348 additions and 4 deletions.
4 changes: 4 additions & 0 deletions src/main/java/org/fcrepo/modeshape/FedoraDatastreams.java
Expand Up @@ -232,6 +232,10 @@ private URI addDatastreamNode(final String dsPath,
ds.setProperty("fedora:created", Calendar.getInstance());
}
ds.setProperty("jcr:lastModified", Calendar.getInstance());

// TODO: I guess we should also have the PID + DSID..
ds.setProperty("dc:identifier", new String[] { ds.getIdentifier() });

session.save();
session.logout();
logger.debug("Finished adding datastream node at path: " + dsPath);
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/org/fcrepo/modeshape/FedoraObjects.java
Expand Up @@ -11,10 +11,7 @@
import java.io.IOException;
import java.util.Calendar;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.*;
import javax.jcr.nodetype.NodeType;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
Expand Down Expand Up @@ -74,6 +71,7 @@ public Response ingest(@PathParam("pid") final String pid)
obj.addMixin("fedora:owned");
obj.setProperty("fedora:ownerId", "Fedo Radmin");
obj.setProperty("jcr:lastModified", Calendar.getInstance());
obj.setProperty("dc:identifier", new String[] { obj.getIdentifier(), pid });
session.save();
session.logout();
logger.debug("Finished ingest with pid: " + pid);
Expand Down Expand Up @@ -146,4 +144,5 @@ public Long getNumObjects() throws RepositoryException {
session.logout();
return numObjects;
}

}
58 changes: 58 additions & 0 deletions src/main/java/org/fcrepo/modeshape/indexer/DublinCore.java
@@ -0,0 +1,58 @@
package org.fcrepo.modeshape.indexer;

import org.fcrepo.modeshape.AbstractResource;
import org.fcrepo.modeshape.indexer.dublincore.AbstractIndexer;
import org.fcrepo.modeshape.indexer.dublincore.IndexFromWellKnownPath;

import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

import java.io.InputStream;
import java.util.List;

import static javax.ws.rs.core.MediaType.TEXT_XML;
import static javax.ws.rs.core.Response.ok;


@Path("/objects/{pid}/oai_dc")
public class DublinCore extends AbstractResource {

@Inject
List<AbstractIndexer> indexers;

@GET
@Produces({ TEXT_XML })
public Response getObjectAsDublinCore(@PathParam("pid") final String pid) throws RepositoryException {
final Session session = repo.login();

try {
if (session.nodeExists("/objects/" + pid)) {
final Node obj = session.getNode("/objects/" + pid);

for(AbstractIndexer indexer : indexers) {
InputStream inputStream = indexer.getStream(obj);

if(inputStream != null) {
return ok(inputStream, TEXT_XML).build();
}
}

return four04;
} else {
return four04;
}

} finally {
session.logout();
}

}

}
@@ -0,0 +1,16 @@
package org.fcrepo.modeshape.indexer.dublincore;


import javax.jcr.Node;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

public abstract class AbstractIndexer {

public AbstractIndexer() {
}

public abstract InputStream getStream(Node node);

}
@@ -0,0 +1,46 @@
package org.fcrepo.modeshape.indexer.dublincore;

import javax.jcr.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

public class IndexFromJcrProperties extends AbstractIndexer {

@Override
public InputStream getStream(Node node) {


String str = "<oai_dc:dc xmlns:oai_dc=\"http://www.openarchives.org/OAI/2.0/oai_dc/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">";

try {
final String[] nameGlobs = new String[] { "dc:*"};
PropertyIterator iter = node.getProperties(nameGlobs);

while(iter.hasNext()) {
Property property = iter.nextProperty();
if(property.isMultiple()) {
for(final Value v : property.getValues()) {
str += "\t<" + property.getName() + ">" + v.getString() + "</" + property.getName() + ">\n";
}
}
else {
str += "\t<" + property.getName() + ">" + property.getValue().getString() + "</" + property.getName() + ">\n";

}
}

str += "</oai_dc:dc>";

try {
return new ByteArrayInputStream(str.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
} catch (RepositoryException e) {
e.printStackTrace();
return null;
}
}
}
@@ -0,0 +1,44 @@
package org.fcrepo.modeshape.indexer.dublincore;

import javax.inject.Inject;
import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.RepositoryException;

import java.io.InputStream;

import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;

public class IndexFromWellKnownPath extends AbstractIndexer {

private String wellKnownPath;

@Override
public InputStream getStream(Node node) {

try {
return getContentInputStream(node);
} catch (RepositoryException e) {
e.printStackTrace();

return null;
}
}

private InputStream getContentInputStream(Node node) throws RepositoryException {
if(node.hasNode(this.wellKnownPath)) {
final Node dc = node.getNode(this.wellKnownPath);

Binary binary = dc.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary();

return binary.getStream();
} else {
return null;
}
}

public void setWellKnownPath(String wellKnownPath) {
this.wellKnownPath = wellKnownPath;
}
}
@@ -0,0 +1,21 @@
package org.fcrepo.modeshape.indexer.dublincore;

import javax.jcr.Node;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

public class WorstCaseIndexer extends AbstractIndexer {

@Override
public InputStream getStream(Node node) {
String str = "<oai_dc:dc xmlns:oai_dc=\"http://www.openarchives.org/OAI/2.0/oai_dc/\" ></oai_dc:dc>";

try {
return new ByteArrayInputStream(str.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
}
12 changes: 12 additions & 0 deletions src/main/resources/fedora-node-types.cnd
Expand Up @@ -16,6 +16,13 @@
*/
<fedora = 'info:fedora'>

/*
* Dublin Core. See:
*
* http://dublincore.org/documents/dcmi-namespace/
*/
<dc = 'http://purl.org/dc/terms/'>


/*
* Any Fedora resource.
Expand All @@ -26,6 +33,11 @@
* Temporary for us until we better understand the use of jcr:created.
*/
- fedora:created (STRING) COPY

/*
* See: http://dublincore.org/documents/dcmi-terms/#elements-identifier
*/
- dc:identifier (STRING) multiple COPY


/*
Expand Down
32 changes: 32 additions & 0 deletions src/main/resources/spring/indexer.xml
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">


<context:annotation-config/>

<bean class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="targetListClass">
<value>java.util.LinkedList</value>
</property>
<property name="sourceList">
<list>
<ref local="DCfromJcrPropertiesIndexer"/>
<ref local="wkpIndexer"/>
</list>
</property>
</bean>

<bean id="wkpIndexer" class="org.fcrepo.modeshape.indexer.dublincore.IndexFromWellKnownPath">
<property name="wellKnownPath" value="DC" />
</bean>


<bean id="DCfromJcrPropertiesIndexer" class="org.fcrepo.modeshape.indexer.dublincore.IndexFromJcrProperties" />


</beans>
1 change: 1 addition & 0 deletions src/main/resources/spring/master.xml
Expand Up @@ -9,5 +9,6 @@
<import resource="classpath:/spring/repo.xml"/>
<import resource="classpath:/spring/rest.xml"/>
<import resource="classpath:/spring/eventing.xml"/>
<import resource="classpath:/spring/indexer.xml"/>

</beans>
1 change: 1 addition & 0 deletions src/main/resources/spring/rest.xml
Expand Up @@ -32,6 +32,7 @@
<bean class="org.fcrepo.modeshape.FedoraNamespaces"/>
<bean class="org.fcrepo.modeshape.FedoraObjects"/>
<bean class="org.fcrepo.modeshape.foxml.FedoraOXML"/>
<bean class="org.fcrepo.modeshape.indexer.DublinCore" />
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="json" value="application/json"/>
Expand Down
76 changes: 76 additions & 0 deletions src/test/java/org/fcrepo/modeshape/indexer/DublinCoreTest.java
@@ -0,0 +1,76 @@
package org.fcrepo.modeshape.indexer;


import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static java.util.regex.Pattern.DOTALL;
import static java.util.regex.Pattern.compile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "/spring-test/rest.xml", "/spring-test/repo.xml", "/spring-test/indexer.xml" })
public class DublinCoreTest {
private static final int SERVER_PORT = 8080;
private static final String HOSTNAME = "localhost";
private static final String serverAddress = "http://" + HOSTNAME + ":"
+ SERVER_PORT + "/";

final private Logger logger = LoggerFactory
.getLogger(DublinCoreTest.class);

final private HttpClient client = new HttpClient();

@Test
public void testJcrPropertiesBasedOaiDc() throws Exception {
PostMethod createObjMethod = new PostMethod(serverAddress
+ "rest/objects/fdsa");
client.executeMethod(createObjMethod);

GetMethod getWorstCaseOaiMethod = new GetMethod(serverAddress
+ "rest/objects/fdsa/oai_dc");
int status = client.executeMethod(getWorstCaseOaiMethod);
assertEquals(200, status);

final String response = getWorstCaseOaiMethod.getResponseBodyAsString();
assertTrue("Didn't find oai_dc!",
compile("oai_dc", DOTALL).matcher(response).find());

assertTrue("Didn't find dc:identifier!",
compile("dc:identifier", DOTALL).matcher(response).find());
}

@Test
public void testWellKnownPathOaiDc() throws Exception {
PostMethod createObjMethod = new PostMethod(serverAddress
+ "rest/objects/lkjh");
client.executeMethod(createObjMethod);


PostMethod createDSMethod = new PostMethod(serverAddress
+ "rest/objects/lkjh/datastreams/DC");

createDSMethod.setRequestEntity(new StringRequestEntity(
"marbles for everyone", null, null));

client.executeMethod(createDSMethod);

GetMethod getWorstCaseOaiMethod = new GetMethod(serverAddress
+ "rest/objects/lkjh/oai_dc");
int status = client.executeMethod(getWorstCaseOaiMethod);
assertEquals(200, status);

final String response = getWorstCaseOaiMethod.getResponseBodyAsString();
assertTrue("Didn't find our datastream!",
compile("marbles for everyone", DOTALL).matcher(response).find());
}
}

0 comments on commit bae91c7

Please sign in to comment.