diff --git a/pom.xml b/pom.xml index 21453b1..a4959e0 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,7 @@ UTF-8 4.0.0-beta-05-SNAPSHOT 2.14.0 + 3.3.2 4.3.5 1.1.0 2.12.1 @@ -136,6 +137,19 @@ org.apache.httpcomponents httpclient + ${httpclient.version} + + + + org.apache.commons + commons-lang3 + ${commons.lang3.version} + + + + org.glassfish.jersey.core + jersey-common + ${jersey.version} @@ -153,6 +167,18 @@ + + + org.apache.jena + jena-arq + ${jena.version} + + + + org.apache.jena + jena-core + ${jena.version} + javax.ws.rs @@ -212,20 +238,6 @@ test - - org.apache.jena - jena-arq - ${jena.version} - test - - - - org.apache.jena - jena-core - ${jena.version} - test - - javax.jcr jcr @@ -259,6 +271,8 @@ **/src/main/java/** **/src/test/java/** + **/examples/fcrepo-camel-solr/src/main/java/** + **/examples/fcrepo-camel-solr-scala/src/main/scala/** target/** diff --git a/src/main/java/org/fcrepo/camel/FedoraEndpoint.java b/src/main/java/org/fcrepo/camel/FedoraEndpoint.java index 8840ed7..9733ca4 100644 --- a/src/main/java/org/fcrepo/camel/FedoraEndpoint.java +++ b/src/main/java/org/fcrepo/camel/FedoraEndpoint.java @@ -34,7 +34,7 @@ @UriEndpoint(scheme = "fcrepo") public class FedoraEndpoint extends DefaultEndpoint { - public static final String FCREPO_BASEURL = "FCREPO_BASEURL"; + public static final String FCREPO_BASE_URL = "FCREPO_BASE_URL"; public static final String FCREPO_IDENTIFIER = "FCREPO_IDENTIFIER"; diff --git a/src/main/java/org/fcrepo/camel/processor/SparqlDeleteProcessor.java b/src/main/java/org/fcrepo/camel/processor/SparqlDeleteProcessor.java new file mode 100644 index 0000000..3cdef86 --- /dev/null +++ b/src/main/java/org/fcrepo/camel/processor/SparqlDeleteProcessor.java @@ -0,0 +1,116 @@ +/** + * Copyright 2014 DuraSpace, Inc. + * + * 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 org.fcrepo.camel.processor; + +import static org.apache.camel.Exchange.HTTP_METHOD; +import static org.apache.camel.Exchange.CONTENT_TYPE; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_BASE_URL; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_IDENTIFIER; +import static org.fcrepo.jms.headers.DefaultMessageFactory.BASE_URL_HEADER_NAME; +import static org.fcrepo.jms.headers.DefaultMessageFactory.IDENTIFIER_HEADER_NAME; +import static com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel; + +import org.apache.camel.Processor; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.commons.lang3.StringUtils; + +import com.hp.hpl.jena.graph.Node_URI; +import com.hp.hpl.jena.graph.Triple; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.StmtIterator; + +import java.io.InputStream; +import java.util.Set; +import java.util.HashSet; +import java.util.List; +import java.util.ArrayList; + +/** + * Represends a message processor that deletes objects from an + * external triplestore. + * + * @author Aaron Coburn + * @since Nov 8, 2014 + */ +public class SparqlDeleteProcessor implements Processor { + /** + * Define how the message should be processed. + */ + public void process(final Exchange exchange) throws Exception { + + final Message in = exchange.getIn(); + final Model model = createDefaultModel().read(in.getBody(InputStream.class), null); + final StmtIterator triples = model.listStatements(); + String subject = null; + + if (in.getHeader(FCREPO_BASE_URL) != null) { + subject = in.getHeader(FCREPO_BASE_URL, String.class); + } else if (in.getHeader(BASE_URL_HEADER_NAME) != null) { + subject = in.getHeader(BASE_URL_HEADER_NAME, String.class); + } else { + throw new Exception("No baseURL header available!"); + } + + if (in.getHeader(FCREPO_IDENTIFIER) != null) { + subject += in.getHeader(FCREPO_IDENTIFIER); + } else if (in.getHeader(IDENTIFIER_HEADER_NAME) != null) { + subject += in.getHeader(IDENTIFIER_HEADER_NAME); + } + + // build list of triples to delete + final Set uris = new HashSet(); + while ( triples.hasNext() ) { + final Triple triple = triples.next().asTriple(); + + // add subject uri, if it is part of this object + if ( triple.getSubject().isURI() ) { + final String uri = ((Node_URI)triple.getSubject()).getURI(); + + if (uriMatches(subject, uri) ) { + uris.add(uri); + } + } + + // add object uri, if it is part of this object + if ( triple.getObject().isURI() ) { + final String uri = ((Node_URI)triple.getObject()).getURI(); + if (uriMatches(subject, uri) ) { + uris.add(uri); + } + } + } + + // build delete commands + final List commands = new ArrayList(); + for (final String uri : uris) { + commands.add("DELETE WHERE { <" + uri + "> ?p ?o }"); + } + + exchange.getIn().setBody(StringUtils.join(commands, ";\n")); + exchange.getIn().setHeader(HTTP_METHOD, "POST"); + exchange.getIn().setHeader(CONTENT_TYPE, "application/sparql-update"); + } + + private static boolean uriMatches(final String resource, final String candidate) { + // All triples that will match this logic are ones that: + // - have a candidate subject or object that equals the target resource of removal, or + // - have a candidate subject or object that is prefixed with the resource of removal + // (therefore catching all children). + return resource.equals(candidate) || candidate.startsWith(resource + "/") + || candidate.startsWith(resource + "#"); + } +} diff --git a/src/main/java/org/fcrepo/camel/processor/SparqlDescribeProcessor.java b/src/main/java/org/fcrepo/camel/processor/SparqlDescribeProcessor.java new file mode 100644 index 0000000..d034206 --- /dev/null +++ b/src/main/java/org/fcrepo/camel/processor/SparqlDescribeProcessor.java @@ -0,0 +1,73 @@ +/** + * Copyright 2014 DuraSpace, Inc. + * + * 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 org.fcrepo.camel.processor; + +import static org.apache.camel.Exchange.HTTP_METHOD; +import static org.apache.camel.Exchange.CONTENT_TYPE; +import static org.apache.camel.Exchange.ACCEPT_CONTENT_TYPE; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_BASE_URL; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_IDENTIFIER; +import static org.fcrepo.jms.headers.DefaultMessageFactory.BASE_URL_HEADER_NAME; +import static org.fcrepo.jms.headers.DefaultMessageFactory.IDENTIFIER_HEADER_NAME; + +import org.apache.camel.Processor; +import org.apache.camel.Exchange; +import org.apache.camel.Message; + +/** + * Represents a Processor class that formulates a Sparql DESCRIBE query + * that is ready to be POSTed to a Sparql endpoint. + * + * The processor expects the following headers: + * org.fcrepo.jms.identifier + * org.fcrepo.jms.baseURL + * each of which can be overridden with the following: + * FCREPO_IDENTIFIER + * FCREPO_BASE_URL + * + * @author Aaron Coburn + * @since November 6, 2014 + */ +public class SparqlDescribeProcessor implements Processor { + /** + * Define how this message should be processed + */ + public void process(final Exchange exchange) throws Exception { + + final Message in = exchange.getIn(); + + String subject = null; + + if (in.getHeader(FCREPO_BASE_URL) != null) { + subject = in.getHeader(FCREPO_BASE_URL, String.class); + } else if (in.getHeader(BASE_URL_HEADER_NAME) != null) { + subject = in.getHeader(BASE_URL_HEADER_NAME, String.class); + } else { + throw new Exception("No baseURL header available!"); + } + + if (in.getHeader(FCREPO_IDENTIFIER) != null) { + subject += in.getHeader(FCREPO_IDENTIFIER); + } else if (in.getHeader(IDENTIFIER_HEADER_NAME) != null) { + subject += in.getHeader(IDENTIFIER_HEADER_NAME); + } + + exchange.getIn().setBody("query=DESCRIBE <" + subject + ">"); + exchange.getIn().setHeader(HTTP_METHOD, "POST"); + exchange.getIn().setHeader(ACCEPT_CONTENT_TYPE, "application/rdf+xml"); + exchange.getIn().setHeader(CONTENT_TYPE, "application/x-www-form-urlencoded"); + } +} diff --git a/src/main/java/org/fcrepo/camel/processor/SparqlInsertProcessor.java b/src/main/java/org/fcrepo/camel/processor/SparqlInsertProcessor.java new file mode 100644 index 0000000..2b41002 --- /dev/null +++ b/src/main/java/org/fcrepo/camel/processor/SparqlInsertProcessor.java @@ -0,0 +1,60 @@ +/** + * Copyright 2014 DuraSpace, Inc. + * + * 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 org.fcrepo.camel.processor; + +import static org.apache.camel.Exchange.HTTP_METHOD; +import static org.apache.camel.Exchange.CONTENT_TYPE; +import static com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel; + +import org.apache.camel.Processor; +import org.apache.camel.Exchange; +import org.apache.camel.Message; + +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.StmtIterator; +import com.hp.hpl.jena.sparql.modify.request.QuadDataAcc; +import com.hp.hpl.jena.sparql.modify.request.UpdateDataInsert; +import com.hp.hpl.jena.update.UpdateRequest; + +import java.io.InputStream; + +/** + * Represents a processor for creating the sparql-update message to + * be passed to an external triplestore. + * + * @author Aaron Coburn + * @since Nov 8, 2014 + */ +public class SparqlInsertProcessor implements Processor { + /** + * Define how the message is processed. + */ + public void process(final Exchange exchange) throws Exception { + + final Message in = exchange.getIn(); + final Model model = createDefaultModel().read(in.getBody(InputStream.class), null, "N-TRIPLE"); + final StmtIterator triples = model.listStatements(); + final QuadDataAcc add = new QuadDataAcc(); + while (triples.hasNext()) { + add.addTriple(triples.nextStatement().asTriple()); + } + final UpdateRequest request = new UpdateRequest(new UpdateDataInsert(add)); + + exchange.getIn().setBody(request.toString()); + exchange.getIn().setHeader(HTTP_METHOD, "POST"); + exchange.getIn().setHeader(CONTENT_TYPE, "application/sparql-update"); + } +} diff --git a/src/test/java/org/fcrepo/camel/SparqlDeleteProcessorTest.java b/src/test/java/org/fcrepo/camel/SparqlDeleteProcessorTest.java new file mode 100644 index 0000000..b210816 --- /dev/null +++ b/src/test/java/org/fcrepo/camel/SparqlDeleteProcessorTest.java @@ -0,0 +1,118 @@ +/** + * Copyright 2014 DuraSpace, Inc. + * + * 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 org.fcrepo.camel.integration; + +import static org.apache.camel.Exchange.HTTP_METHOD; +import static org.apache.camel.Exchange.CONTENT_TYPE; +import static org.fcrepo.jms.headers.DefaultMessageFactory.IDENTIFIER_HEADER_NAME; +import static org.fcrepo.jms.headers.DefaultMessageFactory.BASE_URL_HEADER_NAME; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_IDENTIFIER; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_BASE_URL; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.fcrepo.camel.processor.SparqlDeleteProcessor; +import org.junit.Test; + +/** + * Test adding a non-RDF resource + * @author Aaron Coburn + * @since November 7, 2014 + */ +public class SparqlDeleteProcessorTest extends CamelTestSupport { + + @EndpointInject(uri = "mock:result") + protected MockEndpoint resultEndpoint; + + @Produce(uri = "direct:start") + protected ProducerTemplate template; + + @Test + public void testDelete() throws IOException, InterruptedException { + final String base = "http://localhost/rest"; + final String path = "/path/book3"; + final String incomingDoc = + "" + + " " + + " Middlemarch" + + " " + + " " + + " George Elliot" + + " " + + " Elliot" + + " George" + + " " + + " " + + " " + + ""; + + // Assertions + resultEndpoint.expectedBodiesReceived( + "DELETE WHERE { <" + base + path + "> ?p ?o };\n" + + "DELETE WHERE { <" + base + path + "/appendix> ?p ?o }"); + resultEndpoint.expectedHeaderReceived(CONTENT_TYPE, "application/sparql-update"); + resultEndpoint.expectedHeaderReceived(HTTP_METHOD, "POST"); + + // Test + final Map headers = new HashMap<>(); + headers.put(FCREPO_BASE_URL, base); + headers.put(FCREPO_IDENTIFIER, path); + template.sendBodyAndHeaders(incomingDoc, headers); + + headers.clear(); + headers.put(BASE_URL_HEADER_NAME, base); + headers.put(IDENTIFIER_HEADER_NAME, path); + template.sendBodyAndHeaders(incomingDoc, headers); + + headers.clear(); + headers.put(BASE_URL_HEADER_NAME, base); + headers.put(FCREPO_IDENTIFIER, path); + template.sendBodyAndHeaders(incomingDoc, headers); + + headers.clear(); + headers.put(FCREPO_BASE_URL, base); + headers.put(IDENTIFIER_HEADER_NAME, path); + template.sendBodyAndHeaders(incomingDoc, headers); + + // Confirm that assertions passed + resultEndpoint.expectedMessageCount(4); + resultEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() throws IOException { + from("direct:start") + .process(new SparqlDeleteProcessor()) + .to("mock:result"); + } + }; + } +} diff --git a/src/test/java/org/fcrepo/camel/SparqlDescribeProcessorTest.java b/src/test/java/org/fcrepo/camel/SparqlDescribeProcessorTest.java new file mode 100644 index 0000000..ab19ed6 --- /dev/null +++ b/src/test/java/org/fcrepo/camel/SparqlDescribeProcessorTest.java @@ -0,0 +1,100 @@ +/** + * Copyright 2014 DuraSpace, Inc. + * + * 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 org.fcrepo.camel.integration; + +import static org.apache.camel.Exchange.HTTP_METHOD; +import static org.apache.camel.Exchange.CONTENT_TYPE; +import static org.apache.camel.Exchange.ACCEPT_CONTENT_TYPE; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_IDENTIFIER; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_BASE_URL; +import static org.fcrepo.jms.headers.DefaultMessageFactory.IDENTIFIER_HEADER_NAME; +import static org.fcrepo.jms.headers.DefaultMessageFactory.BASE_URL_HEADER_NAME; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.fcrepo.camel.processor.SparqlDescribeProcessor; +import org.junit.Test; + +/** + * Test adding a non-RDF resource + * @author Aaron Coburn + * @since November 7, 2014 + */ +public class SparqlDescribeProcessorTest extends CamelTestSupport { + + @EndpointInject(uri = "mock:result") + protected MockEndpoint resultEndpoint; + + @Produce(uri = "direct:start") + protected ProducerTemplate template; + + @Test + public void testDescribe() throws IOException, InterruptedException { + final String base = "http://localhost/rest"; + final String path = "/path/a/b/c/d"; + + // Assertions + resultEndpoint.expectedBodiesReceived("query=DESCRIBE <" + base + path + ">"); + resultEndpoint.expectedHeaderReceived(CONTENT_TYPE, "application/x-www-form-urlencoded"); + resultEndpoint.expectedHeaderReceived(HTTP_METHOD, "POST"); + resultEndpoint.expectedHeaderReceived(ACCEPT_CONTENT_TYPE, "application/rdf+xml"); + + // Test + final Map headers = new HashMap<>(); + headers.put(FCREPO_BASE_URL, base); + headers.put(FCREPO_IDENTIFIER, path); + template.sendBodyAndHeaders(null, headers); + + headers.clear(); + headers.put(BASE_URL_HEADER_NAME, base); + headers.put(IDENTIFIER_HEADER_NAME, path); + template.sendBodyAndHeaders(null, headers); + + headers.clear(); + headers.put(BASE_URL_HEADER_NAME, base); + headers.put(FCREPO_IDENTIFIER, path); + template.sendBodyAndHeaders(null, headers); + + headers.clear(); + headers.put(FCREPO_BASE_URL, base); + headers.put(IDENTIFIER_HEADER_NAME, path); + template.sendBodyAndHeaders(null, headers); + + // Confirm that assertions passed + resultEndpoint.expectedMessageCount(4); + resultEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() throws IOException { + from("direct:start") + .process(new SparqlDescribeProcessor()) + .to("mock:result"); + } + }; + } +} diff --git a/src/test/java/org/fcrepo/camel/SparqlInsertProcessorTest.java b/src/test/java/org/fcrepo/camel/SparqlInsertProcessorTest.java new file mode 100644 index 0000000..fbca3cc --- /dev/null +++ b/src/test/java/org/fcrepo/camel/SparqlInsertProcessorTest.java @@ -0,0 +1,119 @@ +/** + * Copyright 2014 DuraSpace, Inc. + * + * 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 org.fcrepo.camel.integration; + +import static org.apache.camel.Exchange.HTTP_METHOD; +import static org.apache.commons.lang3.StringUtils.normalizeSpace; +import static org.apache.commons.lang3.StringUtils.join; +import static org.apache.commons.lang3.ArrayUtils.reverse; +import static org.fcrepo.camel.integration.FedoraTestUtils.getFcrepoEndpointUri; +import static org.fcrepo.camel.integration.FedoraTestUtils.getN3Document; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_BASE_URL; +import static org.fcrepo.camel.FedoraEndpoint.FCREPO_IDENTIFIER; +import static org.fcrepo.jms.headers.DefaultMessageFactory.BASE_URL_HEADER_NAME; +import static org.fcrepo.jms.headers.DefaultMessageFactory.IDENTIFIER_HEADER_NAME; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.fcrepo.camel.processor.SparqlInsertProcessor; +import org.junit.Test; + +/** + * Test adding a non-RDF resource + * @author Aaron Coburn + * @since November 7, 2014 + */ +public class SparqlInsertProcessorTest extends CamelTestSupport { + + @EndpointInject(uri = "mock:result") + protected MockEndpoint resultEndpoint; + + @Produce(uri = "direct:start") + protected ProducerTemplate template; + + @Test + public void testDescribe() throws IOException, InterruptedException { + final String base = "http://localhost/rest"; + final String path = "/path/a/b/c/d"; + final String document = getN3Document(); + + // Reverse the lines as the RDF is serialized in opposite order + final String[] lines = document.split("\n"); + reverse(lines); + + // Assertions + resultEndpoint.expectedBodiesReceived("INSERT DATA { " + join(lines, " ") + " }"); + resultEndpoint.expectedHeaderReceived("Content-Type", "application/sparql-update"); + resultEndpoint.expectedHeaderReceived(HTTP_METHOD, "POST"); + + // Test + final Map headers = new HashMap<>(); + headers.put(FCREPO_BASE_URL, base); + headers.put(FCREPO_IDENTIFIER, path); + template.sendBodyAndHeaders(document, headers); + + headers.clear(); + headers.put(BASE_URL_HEADER_NAME, base); + headers.put(IDENTIFIER_HEADER_NAME, path); + template.sendBodyAndHeaders(document, headers); + + headers.clear(); + headers.put(BASE_URL_HEADER_NAME, base); + headers.put(FCREPO_IDENTIFIER, path); + template.sendBodyAndHeaders(document, headers); + + headers.clear(); + headers.put(FCREPO_BASE_URL, base); + headers.put(IDENTIFIER_HEADER_NAME, path); + template.sendBodyAndHeaders(document, headers); + + // Confirm that assertions passed + resultEndpoint.expectedMessageCount(4); + resultEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() throws IOException { + + final String fcrepo_uri = getFcrepoEndpointUri(); + + from("direct:start") + .process(new SparqlInsertProcessor()) + // Normalize the whitespace to make it easier to compare + .process(new Processor() { + public void process(final Exchange exchange) throws Exception { + final String payload = exchange.getIn().getBody(String.class); + exchange.getIn().setBody(normalizeSpace(payload)); + } + }) + .to("mock:result"); + } + }; + } +} diff --git a/src/test/java/org/fcrepo/camel/integration/FedoraSparqlIT.java b/src/test/java/org/fcrepo/camel/integration/FedoraSparqlIT.java new file mode 100644 index 0000000..86ab1d8 --- /dev/null +++ b/src/test/java/org/fcrepo/camel/integration/FedoraSparqlIT.java @@ -0,0 +1,124 @@ +/** + * Copyright 2014 DuraSpace, Inc. + * + * 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 org.fcrepo.camel.integration; + +import static org.apache.camel.Exchange.CONTENT_TYPE; +import static org.apache.camel.Exchange.HTTP_METHOD; +import static java.lang.System.getProperty; + +import java.util.Map; +import java.util.HashMap; +import java.io.IOException; + +import org.fcrepo.camel.processor.SparqlInsertProcessor; +import org.fcrepo.camel.processor.SparqlDescribeProcessor; +import org.fcrepo.camel.processor.SparqlDeleteProcessor; + +import org.apache.camel.Produce; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.EndpointInject; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.builder.xml.XPathBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.runner.RunWith; +import org.junit.Test; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * Represents an integration test for interacting with an external triplestore. + * + * @author Aaron Coburn + * @since Nov 8, 2014 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({"/spring-test/test-container.xml"}) +public class FedoraSparqlIT extends CamelTestSupport { + + @EndpointInject(uri = "mock:result") + protected MockEndpoint resultEndpoint; + + @Produce(uri = "direct:start") + protected ProducerTemplate template; + + @Test + public void testSparql() throws Exception { + // Assertions + resultEndpoint.expectedMessageCount(1); + + // Setup + final Map headers = new HashMap(); + headers.put(HTTP_METHOD, "POST"); + headers.put(CONTENT_TYPE, "text/turtle"); + + final String fullPath = template.requestBodyAndHeaders( + "direct:setup", FedoraTestUtils.getTurtleDocument(), headers, String.class); + + final String identifier = fullPath.replaceAll(FedoraTestUtils.getFcrepoBaseUrl(), ""); + + // Test + final Map testHeaders = new HashMap(); + testHeaders.put("FCREPO_IDENTIFIER", identifier); + testHeaders.put("org.fcrepo.jms.baseURL", "http://localhost:8080/fcrepo4/rest"); + template.sendBodyAndHeaders(null, testHeaders); + + // Teardown + final Map teardownHeaders = new HashMap(); + teardownHeaders.put(Exchange.HTTP_METHOD, "DELETE"); + teardownHeaders.put("FCREPO_IDENTIFIER", identifier); + template.sendBodyAndHeaders("direct:teardown", null, teardownHeaders); + + // Confirm that the assertions passed + resultEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() throws IOException { + + final String fcrepo_uri = FedoraTestUtils.getFcrepoEndpointUri(); + final String fuseki_url = "localhost:" + getProperty("test.fuseki.port", "3030"); + final Processor sparqlInsert = new SparqlInsertProcessor(); + final XPathBuilder titleXpath = new XPathBuilder("/rdf:RDF/rdf:Description/dc:title/text()"); + titleXpath.namespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + titleXpath.namespace("dc", "http://purl.org/dc/elements/1.1/"); + + from("direct:setup") + .to(fcrepo_uri); + + from("direct:start") + .process(new SparqlDescribeProcessor()) + .to("http4:" + fuseki_url + "/test/query") + //.log("${body}") + .process(new SparqlDeleteProcessor()) + .to("http4:" + fuseki_url + "/test/update") + .setHeader(Exchange.HTTP_METHOD).constant("GET") + .to(fcrepo_uri + "?accept=application/n-triples") + .process(new SparqlInsertProcessor()) + .to("http4:" + fuseki_url + "/test/update") + .to("mock:result"); + + from("direct:teardown") + .to(fcrepo_uri) + .to(fcrepo_uri + "?tombstone=true"); + } + }; + } +} diff --git a/src/test/java/org/fcrepo/camel/integration/FedoraTestUtils.java b/src/test/java/org/fcrepo/camel/integration/FedoraTestUtils.java index 1d1c9c5..d89e919 100644 --- a/src/test/java/org/fcrepo/camel/integration/FedoraTestUtils.java +++ b/src/test/java/org/fcrepo/camel/integration/FedoraTestUtils.java @@ -62,6 +62,14 @@ public static String getTurtleDocument() { "<> dc:title \"some title\" ."; } + /** + * Retrieve an N3 document + */ + public static String getN3Document() { + return " \"Author\" .\n" + + " \"Title\" ."; + } + /** * Retrieve a simple text document */