001/*
002 * Copyright 2016 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.serialization;
017
018import static org.apache.camel.LoggingLevel.INFO;
019import static org.apache.camel.LoggingLevel.DEBUG;
020import static org.apache.camel.Exchange.FILE_NAME;
021import static org.apache.camel.builder.PredicateBuilder.not;
022import static org.apache.camel.builder.PredicateBuilder.or;
023import static org.apache.camel.component.exec.ExecBinding.EXEC_COMMAND_ARGS;
024import static org.fcrepo.camel.FcrepoHeaders.FCREPO_IDENTIFIER;
025import static org.fcrepo.camel.JmsHeaders.EVENT_TYPE;
026import static org.fcrepo.camel.JmsHeaders.IDENTIFIER;
027import static org.fcrepo.camel.RdfNamespaces.RDF;
028import static org.fcrepo.camel.RdfNamespaces.REPOSITORY;
029
030import org.apache.camel.builder.RouteBuilder;
031import org.apache.camel.builder.xml.Namespaces;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034
035/**
036 *
037 * A router for serializing fedora objects and binaries.
038 *
039 * @author Bethany Seeger
040 * @since 2015-09-28
041 */
042
043public class SerializationRouter extends RouteBuilder {
044
045    private static final Logger LOGGER = LoggerFactory.getLogger(SerializationRouter.class);
046
047    private static final String RESOURCE_DELETION = "http://fedora.info/definitions/v4/event#ResourceDeletion";
048
049    private static final String isBinaryResourceXPath =
050        "/rdf:RDF/rdf:Description/rdf:type[@rdf:resource=\"" + REPOSITORY + "Binary\"]";
051    /**
052     * Configure the message route workflow
053     *
054     */
055
056    public void configure() throws Exception {
057
058        final Namespaces ns = new Namespaces("rdf", RDF).add("fedora", REPOSITORY);
059
060        /**
061         * A generic error handler (specific to this RouteBuilder)
062         */
063        onException(Exception.class)
064                .maximumRedeliveries("{{error.maxRedeliveries}}")
065                .log("Index Routing Error: ${routeId}");
066
067        /**
068         * Handle Serialization Events
069         */
070        from("{{input.stream}}")
071            .routeId("FcrepoSerialization")
072            .setHeader(FCREPO_IDENTIFIER).header(IDENTIFIER)
073            .filter(not(or(header(FCREPO_IDENTIFIER).startsWith(simple("{{audit.container}}/")),
074                    header(FCREPO_IDENTIFIER).isEqualTo(simple("{{audit.container}}")))))
075            .choice()
076                // this clause supports Fedora 4.5.1 and earlier but may be removed in a future release
077                .when(header(EVENT_TYPE).isEqualTo(REPOSITORY + "NODE_REMOVED"))
078                    .to("direct:delete")
079                .when(header(EVENT_TYPE).isEqualTo(RESOURCE_DELETION))
080                    .to("direct:delete")
081                .otherwise()
082                    .multicast().to("direct:metadata", "direct:binary");
083
084        from("{{serialization.stream}}")
085            .routeId("FcrepoReSerialization")
086            .filter(not(or(header(FCREPO_IDENTIFIER).startsWith(simple("{{audit.container}}/")),
087                    header(FCREPO_IDENTIFIER).isEqualTo(simple("{{audit.container}}")))))
088            .multicast().to("direct:metadata", "direct:binary");
089
090        from("direct:metadata")
091            .routeId("FcrepoSerializationMetadataUpdater")
092            .to("fcrepo:{{fcrepo.baseUrl}}?accept={{serialization.mimeType}}")
093            .log(INFO, LOGGER,
094                    "Serializing object ${headers[CamelFcrepoIdentifier]}")
095            .setHeader(FILE_NAME)
096                .simple("${headers[CamelFcrepoIdentifier]}.{{serialization.extension}}")
097            .log(DEBUG, LOGGER, "filename is ${headers[CamelFileName]}")
098            .to("file://{{serialization.descriptions}}");
099
100        from("direct:binary")
101            .routeId("FcrepoSerializationBinaryUpdater")
102            .filter().simple("{{serialization.includeBinaries}} == 'true'")
103            .to("fcrepo:{{fcrepo.baseUrl}}?preferInclude=PreferMinimalContainer" +
104                    "&accept=application/rdf+xml")
105            .filter().xpath(isBinaryResourceXPath, ns)
106            .log(INFO, LOGGER, "Writing binary ${headers[CamelFcrepoIdentifier]}")
107            .to("fcrepo:{{fcrepo.baseUrl}}?metadata=false")
108            .setHeader(FILE_NAME).header(FCREPO_IDENTIFIER)
109            .log(DEBUG, LOGGER, "header filename is: ${headers[CamelFileName]}")
110            .to("file://{{serialization.binaries}}");
111
112        from("direct:delete")
113            .routeId("FcrepoSerializationDeleter")
114            .setHeader(EXEC_COMMAND_ARGS).simple(
115                    "-rf {{serialization.descriptions}}${headers[CamelFcrepoIdentifier]}.{{serialization.extension}} " +
116                    "{{serialization.descriptions}}${headers[CamelFcrepoIdentifier]} " +
117                    "{{serialization.binaries}}${headers[CamelFcrepoIdentifier]}")
118            .to("exec:rm");
119    }
120}