001/** 002 * Copyright 2015 DuraSpace, Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.fcrepo.camel.reindexing; 017 018import static org.fcrepo.camel.FcrepoHeaders.FCREPO_BASE_URL; 019import static org.slf4j.LoggerFactory.getLogger; 020 021import javax.xml.transform.stream.StreamSource; 022 023import org.apache.camel.Exchange; 024import org.apache.camel.LoggingLevel; 025import org.apache.camel.PropertyInject; 026import org.apache.camel.builder.RouteBuilder; 027import org.apache.camel.builder.xml.Namespaces; 028import org.fcrepo.client.HttpMethods; 029import org.fcrepo.camel.RdfNamespaces; 030import org.slf4j.Logger; 031 032/** 033 * A content router for handling JMS events. 034 * 035 * @author Aaron Coburn 036 */ 037public class ReindexingRouter extends RouteBuilder { 038 039 private static final Logger LOGGER = getLogger(ReindexingRouter.class); 040 private static final int BAD_REQUEST = 400; 041 042 @PropertyInject(value = "rest.port", defaultValue = "9080") 043 private String port; 044 045 /** 046 * Configure the message route workflow. 047 */ 048 public void configure() throws Exception { 049 050 restConfiguration().component("jetty").port( 051 System.getProperty("fcrepo.dynamic.reindexing.port", port)); 052 053 final Namespaces ns = new Namespaces("rdf", RdfNamespaces.RDF); 054 ns.add("ldp", RdfNamespaces.LDP); 055 056 /** 057 * A generic error handler (specific to this RouteBuilder) 058 */ 059 onException(Exception.class) 060 .maximumRedeliveries("{{error.maxRedeliveries}}") 061 .log("Index Routing Error: ${routeId}"); 062 063 /** 064 * Expose a RESTful endpoint for re-indexing 065 */ 066 rest("{{rest.prefix}}") 067 .get().to("direct:usage") 068 .post().consumes("application/json").to("direct:reindex"); 069 070 from("direct:usage") 071 .routeId("FcrepoReindexingUsage") 072 .setHeader(ReindexingHeaders.REST_PREFIX).simple("{{rest.prefix}}") 073 .setHeader(ReindexingHeaders.REST_PORT).simple("{{rest.port}}") 074 .setHeader(FCREPO_BASE_URL).simple("{{fcrepo.baseUrl}}") 075 .process(new UsageProcessor()); 076 077 /** 078 * A Re-indexing endpoint, setting where in the fcrepo hierarchy 079 * a re-indexing operation should begin. 080 */ 081 from("direct:reindex") 082 .routeId("FcrepoReindexingReindex") 083 .setHeader(ReindexingHeaders.REST_PREFIX).simple("{{rest.prefix}}") 084 .setHeader(FCREPO_BASE_URL).simple("{{fcrepo.baseUrl}}") 085 .process(new RestProcessor()) 086 .choice() 087 .when(header(Exchange.HTTP_RESPONSE_CODE).isGreaterThanOrEqualTo(BAD_REQUEST)) 088 .endChoice() 089 .when(header(ReindexingHeaders.RECIPIENTS).isEqualTo("")) 090 .transform().simple("No endpoints configured for indexing") 091 .endChoice() 092 .otherwise() 093 .log(LoggingLevel.INFO, LOGGER, "Initial indexing path: ${headers[CamelFcrepoIdentifier]}") 094 .inOnly("{{reindexing.stream}}?disableTimeToLive=true") 095 .setHeader(Exchange.CONTENT_TYPE).constant("text/plain") 096 .transform().simple("Indexing started at ${headers[CamelFcrepoIdentifier]}"); 097 098 /** 099 * A route that traverses through a fedora heirarchy 100 * indexing nodes, as appropriate. 101 */ 102 from("{{reindexing.stream}}?asyncConsumer=true") 103 .routeId("FcrepoReindexingTraverse") 104 .inOnly("direct:recipients") 105 .removeHeaders("CamelHttp*") 106 .setHeader(Exchange.HTTP_METHOD).constant(HttpMethods.GET) 107 .to("fcrepo:{{fcrepo.baseUrl}}?preferInclude=PreferContainment&preferOmit=ServerManaged") 108 .convertBodyTo(StreamSource.class) 109 .split().xtokenize("/rdf:RDF/rdf:Description/ldp:contains", 'i', ns).streaming() 110 .transform().xpath("/ldp:contains/@rdf:resource", String.class, ns) 111 .process(new PathProcessor()) 112 .inOnly("{{reindexing.stream}}?disableTimeToLive=true"); 113 114 /** 115 * Send the message to all of the pre-determined endpoints 116 */ 117 from("direct:recipients") 118 .routeId("FcrepoReindexingRecipients") 119 .recipientList(header(ReindexingHeaders.RECIPIENTS)) 120 .ignoreInvalidEndpoints(); 121 } 122}