001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.camel.serialization;
019
020import static org.apache.camel.LoggingLevel.INFO;
021import static org.apache.camel.LoggingLevel.DEBUG;
022import static org.apache.camel.Exchange.FILE_NAME;
023import static org.apache.camel.builder.PredicateBuilder.not;
024import static org.apache.camel.builder.PredicateBuilder.or;
025import static org.apache.camel.component.exec.ExecBinding.EXEC_COMMAND_ARGS;
026import static org.fcrepo.camel.FcrepoHeaders.FCREPO_IDENTIFIER;
027import static org.fcrepo.camel.JmsHeaders.EVENT_TYPE;
028import static org.fcrepo.camel.JmsHeaders.IDENTIFIER;
029import static org.fcrepo.camel.RdfNamespaces.RDF;
030import static org.fcrepo.camel.RdfNamespaces.REPOSITORY;
031
032import org.apache.camel.builder.RouteBuilder;
033import org.apache.camel.builder.xml.Namespaces;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036
037/**
038 *
039 * A router for serializing fedora objects and binaries.
040 *
041 * @author Bethany Seeger
042 * @since 2015-09-28
043 */
044
045public class SerializationRouter extends RouteBuilder {
046
047    private static final Logger LOGGER = LoggerFactory.getLogger(SerializationRouter.class);
048
049    private static final String RESOURCE_DELETION = "http://fedora.info/definitions/v4/event#ResourceDeletion";
050
051    private static final String isBinaryResourceXPath =
052        "/rdf:RDF/rdf:Description/rdf:type[@rdf:resource=\"" + REPOSITORY + "Binary\"]";
053    /**
054     * Configure the message route workflow
055     *
056     */
057
058    public void configure() throws Exception {
059
060        final Namespaces ns = new Namespaces("rdf", RDF).add("fedora", REPOSITORY);
061
062        /**
063         * A generic error handler (specific to this RouteBuilder)
064         */
065        onException(Exception.class)
066                .maximumRedeliveries("{{error.maxRedeliveries}}")
067                .log("Index Routing Error: ${routeId}");
068
069        /**
070         * Handle Serialization Events
071         */
072        from("{{input.stream}}")
073            .routeId("FcrepoSerialization")
074            .setHeader(FCREPO_IDENTIFIER).header(IDENTIFIER)
075            .filter(not(or(header(FCREPO_IDENTIFIER).startsWith(simple("{{audit.container}}/")),
076                    header(FCREPO_IDENTIFIER).isEqualTo(simple("{{audit.container}}")))))
077            .choice()
078                // this clause supports Fedora 4.5.1 and earlier but may be removed in a future release
079                .when(header(EVENT_TYPE).isEqualTo(REPOSITORY + "NODE_REMOVED"))
080                    .to("direct:delete")
081                .when(header(EVENT_TYPE).isEqualTo(RESOURCE_DELETION))
082                    .to("direct:delete")
083                .otherwise()
084                    .multicast().to("direct:metadata", "direct:binary");
085
086        from("{{serialization.stream}}")
087            .routeId("FcrepoReSerialization")
088            .filter(not(or(header(FCREPO_IDENTIFIER).startsWith(simple("{{audit.container}}/")),
089                    header(FCREPO_IDENTIFIER).isEqualTo(simple("{{audit.container}}")))))
090            .multicast().to("direct:metadata", "direct:binary");
091
092        from("direct:metadata")
093            .routeId("FcrepoSerializationMetadataUpdater")
094            .to("fcrepo:{{fcrepo.baseUrl}}?accept={{serialization.mimeType}}")
095            .log(INFO, LOGGER,
096                    "Serializing object ${headers[CamelFcrepoIdentifier]}")
097            .setHeader(FILE_NAME)
098                .simple("${headers[CamelFcrepoIdentifier]}.{{serialization.extension}}")
099            .log(DEBUG, LOGGER, "filename is ${headers[CamelFileName]}")
100            .to("file://{{serialization.descriptions}}");
101
102        from("direct:binary")
103            .routeId("FcrepoSerializationBinaryUpdater")
104            .filter().simple("{{serialization.includeBinaries}} == 'true'")
105            .to("fcrepo:{{fcrepo.baseUrl}}?preferInclude=PreferMinimalContainer" +
106                    "&accept=application/rdf+xml")
107            .filter().xpath(isBinaryResourceXPath, ns)
108            .log(INFO, LOGGER, "Writing binary ${headers[CamelFcrepoIdentifier]}")
109            .to("fcrepo:{{fcrepo.baseUrl}}?metadata=false")
110            .setHeader(FILE_NAME).header(FCREPO_IDENTIFIER)
111            .log(DEBUG, LOGGER, "header filename is: ${headers[CamelFileName]}")
112            .to("file://{{serialization.binaries}}");
113
114        from("direct:delete")
115            .routeId("FcrepoSerializationDeleter")
116            .setHeader(EXEC_COMMAND_ARGS).simple(
117                    "-rf {{serialization.descriptions}}${headers[CamelFcrepoIdentifier]}.{{serialization.extension}} " +
118                    "{{serialization.descriptions}}${headers[CamelFcrepoIdentifier]} " +
119                    "{{serialization.binaries}}${headers[CamelFcrepoIdentifier]}")
120            .to("exec:rm");
121    }
122}