001/*
002 * The contents of this file are subject to the license and copyright
003 * detailed in the LICENSE and NOTICE files at the root of the source
004 * tree.
005 */
006package org.fcrepo.camel.httpforwarding;
007
008import org.apache.camel.LoggingLevel;
009import org.apache.camel.builder.RouteBuilder;
010import org.fcrepo.camel.common.processor.AddBasicAuthProcessor;
011import org.apache.camel.support.builder.Namespaces;
012import org.fcrepo.camel.processor.EventProcessor;
013import org.slf4j.Logger;
014import org.springframework.beans.factory.annotation.Autowired;
015
016import static org.apache.camel.builder.PredicateBuilder.in;
017import static org.apache.camel.builder.PredicateBuilder.not;
018import static org.apache.camel.builder.PredicateBuilder.or;
019import static org.fcrepo.camel.FcrepoHeaders.FCREPO_URI;
020import static java.util.stream.Collectors.toList;
021import static org.fcrepo.camel.processor.ProcessorUtils.tokenizePropertyPlaceholder;
022
023import static org.apache.camel.Exchange.CONTENT_TYPE;
024import static org.apache.camel.Exchange.HTTP_METHOD;
025import static org.fcrepo.camel.FcrepoHeaders.FCREPO_EVENT_TYPE;
026import static org.slf4j.LoggerFactory.getLogger;
027
028/**
029 * A content router for handling JMS events.
030 *
031 * @author Geoff Scholl
032 * @author Demian Katz
033 */
034public class HttpRouter extends RouteBuilder {
035
036    private static final Logger LOGGER = getLogger(HttpRouter.class);
037
038    @Autowired
039    private FcrepoHttpForwardingConfig config;
040
041    /**
042     * Configure the message route workflow.
043     */
044    public void configure() throws Exception {
045
046        final Namespaces ns = new Namespaces("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
047        ns.add("indexing", "http://fedora.info/definitions/v4/indexing#");
048        ns.add("ldp", "http://www.w3.org/ns/ldp#");
049
050        /*
051         * A generic error handler (specific to this RouteBuilder)
052         */
053        onException(Exception.class)
054            .maximumRedeliveries(config.getMaxRedeliveries())
055            .log("Index Routing Error: ${routeId}");
056
057        /*
058         * route a message to the proper queue
059         */
060        from(config.getInputStream())
061            .routeId("FcrepoHttpRouter")
062            .process(new EventProcessor())
063            .log(LoggingLevel.TRACE, "Received message from Fedora routing to index.http")
064            .to("direct:add.type.to.http.message");
065
066        /*
067         * Handle re-index events
068         */
069        from(config.getReindexStream())
070            .routeId("FcrepoHttpReindex")
071            .to("direct:add.type.to.http.message");
072
073        /*
074         * Add event type header to message; we want to use the header.org.fcrepo.jms.eventtype
075         * value when it is available. If it is unset, that likely indicates a reindex operation,
076         * in which case we should default to an Update.
077         */
078        from("direct:add.type.to.http.message")
079            .routeId("FcrepoHttpAddType")
080            .choice()
081            .when(simple("${header.org.fcrepo.jms.eventtype}"))
082                .setHeader(FCREPO_EVENT_TYPE).simple("${header.org.fcrepo.jms.eventtype}")
083                .to("direct:send.to.http")
084            .otherwise()
085                .setHeader(FCREPO_EVENT_TYPE).constant("https://www.w3.org/ns/activitystreams#Update")
086                .to("direct:send.to.http");
087
088        /*
089         * Forward message to Http
090         */
091        from("direct:send.to.http").routeId("FcrepoHttpSend")
092            .filter(not(in(tokenizePropertyPlaceholder(getContext(), config.getFilterContainers(), ",").stream()
093                .map(uri -> or(
094                    header(FCREPO_URI).startsWith(constant(uri + "/")),
095                    header(FCREPO_URI).isEqualTo(constant(uri))))
096                .collect(toList()))))
097            .log(LoggingLevel.INFO, LOGGER, "sending ${headers[CamelFcrepoUri]} to http endpoint...")
098            .to("mustache:org/fcrepo/camel/httpforwarding/httpMessage.mustache")
099            .setHeader(HTTP_METHOD).constant("POST")
100            .setHeader(CONTENT_TYPE).constant("application/json")
101            .process(new AddBasicAuthProcessor(config.getHttpAuthUsername(), config.getHttpAuthPassword()))
102            .to(config.getHttpBaseUrl().isEmpty() ? "direct:http.baseurl.missing" : config.getHttpBaseUrl());
103
104        /*
105         * Stop the route if configuration is incomplete.
106         */
107        from("direct:http.baseurl.missing")
108            .routeId("FcrepoHttpBaseUrlMissing")
109            .log(LoggingLevel.ERROR, LOGGER, "Cannot forward HTTP message because http.baseUrl property is empty.")
110            .stop();
111    }
112}