Commit eedffd7b authored by acoburn's avatar acoburn
Browse files

Merge branch 'jsonld-cache-service'

parents 1c9e989d b04f583b
......@@ -3,6 +3,8 @@ Repository JSON-LD compaction service
This collection of camel routes exposes an HTTP endpoint for
generating compact JSON-LD serializations of Fedora resources.
It also automatically replicates these compact resources in
an external key-value system (this example uses Riak).
Building
--------
......@@ -34,6 +36,14 @@ In the event of failure, the maximum number of times a redelivery will be attemp
error.maxRedeliveries=10
The JMS broker URL
jms.brokerUrl=tcp://localhost:61616
The message broker event stream
activemq:topic:fedora
The base url of the fedora repository
fcrepo.baseUrl=localhost:8080/fcrepo/rest
......@@ -46,6 +56,14 @@ The port on which the service is made availalbe
rest.port=13431
The riak hostname
riak.host=localhost:8098
The riak path prefix
riak.prefix=/buckets/fcrepo/keys
By editing this file, any currently running routes will be immediately redeployed
with the new values.
......
......@@ -15,8 +15,7 @@
<name>JSON-LD AppCache Workflow</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<osgi.export.packages>edu.amherst.acdc.jsonld.cache</osgi.export.packages>
</properties>
<dependencies>
......@@ -32,6 +31,14 @@
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty9</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http4</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-camel</artifactId>
</dependency>
<dependency>
<groupId>org.fcrepo.camel</groupId>
<artifactId>fcrepo-camel</artifactId>
......
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.amherst.acdc.jsonld.cache;
import static org.apache.camel.Exchange.HTTP_RESPONSE_CODE;
import static org.apache.camel.Exchange.HTTP_PATH;
import static org.apache.camel.Exchange.HTTP_METHOD;
import static org.fcrepo.camel.FcrepoHeaders.FCREPO_IDENTIFIER;
import static org.fcrepo.camel.FcrepoHeaders.FCREPO_BASE_URL;
import static org.fcrepo.camel.JmsHeaders.EVENT_TYPE;
import static org.fcrepo.camel.JmsHeaders.IDENTIFIER;
import static org.fcrepo.camel.RdfNamespaces.REPOSITORY;
//import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
/**
* A content router for handling JMS events.
*
* @author Aaron Coburn
*/
public class EventRouter extends RouteBuilder {
/**
* Configure the message route workflow.
*/
public void configure() throws Exception {
/**
* A generic error handler (specific to this RouteBuilder)
*/
onException(Exception.class)
.maximumRedeliveries("{{error.maxRedeliveries}}")
.log("Event Routing Error: ${routeId}");
from("{{input.stream}}")
.setHeader(FCREPO_IDENTIFIER).simple("${headers[" + IDENTIFIER + "]}")
.choice()
.when(header(EVENT_TYPE).isEqualTo(REPOSITORY + "NODE_REMOVED"))
.to("direct:delete")
.otherwise()
.to("direct:update");
from("jetty:http://0.0.0.0:{{rest.port}}/jsonld?" +
"matchOnUriPrefix=true&sendServerVersion=false&httpMethodRestrict=GET,PUT,DELETE")
.routeId("JsonLdRouter")
.setHeader(FCREPO_IDENTIFIER).simple("${headers[" + HTTP_PATH + "]}")
.choice()
.when(header(HTTP_METHOD).isEqualTo("GET")).to("direct:get")
.when(header(HTTP_METHOD).isEqualTo("PUT")).to("direct:update")
.when(header(HTTP_METHOD).isEqualTo("DELETE")).to("direct:delete");
from("direct:update")
.routeId("JsonLdUpdate")
.to("direct:get")
.filter(header(HTTP_RESPONSE_CODE).isEqualTo(200))
.setHeader(HTTP_METHOD).constant("PUT")
.process(new RiakKeyBuilder())
.log("Updating cache entry for: ${headers[CamelFcrepoIdentifier]}")
.to("http4://{{riak.host}}");
from("direct:delete")
.routeId("JsonLdDelete")
.setHeader(HTTP_METHOD).constant("DELETE")
.process(new RiakKeyBuilder())
.log("Deleting cache entry for: ${headers[CamelFcrepoIdentifier]}")
.to("http4://{{riak.host}}");
from("direct:get")
.routeId("JsonLdGet")
.to("direct:getResource")
.filter(header(HTTP_RESPONSE_CODE).isEqualTo(200))
.log("Compacting resource ${headers[CamelFcrepoIdentifier]}")
.to("direct:compact");
from("direct:getResource")
.routeId("JsonLdResource")
.removeHeader("breadcrumId")
.removeHeader("Accept")
.removeHeader("User-Agent")
.setHeader(FCREPO_BASE_URL).simple("{{fcrepo.baseUrl}}")
.to("fcrepo:{{fcrepo.baseUrl}}?accept=application/ld+json&throwExceptionOnFailure=false");
}
}
package edu.amherst.acdc.jsonld.cache;
import java.io.IOException;
import java.net.URLEncoder;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.RuntimeCamelException;
import org.fcrepo.camel.FcrepoHeaders;
/**
* @author Aaron Coburn
*/
public class RiakKeyBuilder implements Processor {
/**
* Define how the message should be processed.
*
* @param exchange the current camel message exchange
*/
public void process(final Exchange exchange) throws IOException {
final Message in = exchange.getIn();
final CamelContext ctx = exchange.getContext();
final StringBuilder key = new StringBuilder();
try {
final String prefix = ctx.resolvePropertyPlaceholders("{{riak.prefix}}");
key.append(prefix);
if (!prefix.endsWith("/")) {
key.append("/");
}
} catch (final Exception ex) {
throw new RuntimeCamelException("Could not resolve properties", ex);
}
key.append(URLEncoder.encode(
in.getHeader(FcrepoHeaders.FCREPO_IDENTIFIER, String.class), "UTF-8"));
in.setHeader(Exchange.HTTP_PATH, key.toString());
}
}
......@@ -11,38 +11,24 @@
<cm:property-placeholder persistent-id="edu.amherst.acdc.jsonld.cache" update-strategy="reload">
<cm:default-properties>
<cm:property name="error.maxRedeliveries" value="10"/>
<cm:property name="jms.brokerUrl" value="tcp://localhost:61616"/>
<cm:property name="input.stream" value="activemq:topic:fedora"/>
<cm:property name="rest.port" value="13431"/>
<cm:property name="jsonld.context" value="https://acdc.amherst.edu/jsonld/context.json"/>
<cm:property name="fcrepo.baseUrl" value="localhost:8080/fcrepo/rest"/>
<cm:property name="riak.host" value="localhost:8098"/>
<cm:property name="riak.prefix" value="/buckets/fcrepo/keys"/>
</cm:default-properties>
</cm:property-placeholder>
<reference id="jsonldService" interface="edu.amherst.acdc.jsonld.JsonLdService" filter="(osgi.jndi.service.name=jsonld)" />
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="JsonLdCompactHttp">
<from uri="jetty:http://0.0.0.0:{{rest.port}}/compact?matchOnUriPrefix=true&amp;httpMethodRestrict=GET&amp;sendServerVersion=false"/>
<to uri="direct:getResource"/>
<filter>
<simple>${header[CamelHttpResponseCode]} == 200</simple>
<log message="Converting resource ${headers[CamelFcrepoIdentifier]}"/>
<to uri="direct:compact"/>
</filter>
</route>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="${jms.brokerUrl}"/>
</bean>
<route id="JsonLdResource">
<from uri="direct:getResource"/>
<removeHeaders pattern="breadcrumbId"/>
<removeHeaders pattern="Accept"/>
<removeHeaders pattern="User-Agent"/>
<setHeader headerName="CamelFcrepoIdentifier">
<simple>${headers[CamelHttpPath]}</simple>
</setHeader>
<setHeader headerName="CamelFcrepoBaseUrl">
<simple>{{fcrepo.baseUrl}}</simple>
</setHeader>
<to uri="fcrepo:{{fcrepo.baseUrl}}?accept=application/ld+json&amp;throwExceptionOnFailure=false"/>
</route>
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<package>edu.amherst.acdc.jsonld.cache</package>
<route id="JsonLdCompaction">
<from uri="direct:compact"/>
......
......@@ -134,7 +134,8 @@ public class JsonLdServiceImpl implements JsonLdService {
}
private Predicate<Map<String, Object>> filterExport = x -> {
return x.containsKey("@id") && !x.get("@id").toString().endsWith("/fcr:export?format=jcr/xml");
return x.containsKey("@id") && !(x.get("@id").toString().endsWith("/fcr:export?format=jcr/xml")
|| x.get("@id").toString().equals("http://fedora.info/definitions/v4/repository#jcr/xml"));
};
private Function<Object, String> stringify = x -> {
......
......@@ -90,6 +90,8 @@
<feature version="${camel.version}">camel</feature>
<feature version="${camel.version}">camel-blueprint</feature>
<feature version="${camel.version}">camel-jetty9</feature>
<feature version="${camel.version}">camel-http4</feature>
<feature version="${activemq.version}">activemq-camel</feature>
<feature version="${fcrepo-camel.version}">fcrepo-camel</feature>
<bundle>mvn:edu.amherst.acdc/acrepo-jsonld-cache/${project.version}</bundle>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment