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.processor;
019
020import static org.apache.camel.Exchange.CONTENT_TYPE;
021import static org.apache.camel.Exchange.HTTP_METHOD;
022import static org.apache.http.entity.ContentType.parse;
023import static org.apache.jena.rdf.model.ResourceFactory.createProperty;
024import static org.apache.jena.rdf.model.ResourceFactory.createResource;
025import static org.apache.jena.rdf.model.ResourceFactory.createStatement;
026import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
027import static org.apache.jena.riot.RDFDataMgr.read;
028import static org.apache.jena.riot.RDFDataMgr.write;
029import static org.apache.jena.riot.RDFFormat.JSONLD;
030import static org.apache.jena.riot.RDFLanguages.contentTypeToLang;
031import static org.fcrepo.camel.processor.ProcessorUtils.getSubjectUri;
032
033import java.io.ByteArrayOutputStream;
034import java.io.InputStream;
035import java.io.IOException;
036import java.util.concurrent.atomic.AtomicInteger;
037
038import org.apache.jena.rdf.model.Model;
039import org.apache.jena.rdf.model.Property;
040import org.apache.jena.rdf.model.Resource;
041import org.apache.camel.Exchange;
042import org.apache.camel.Message;
043import org.apache.camel.NoSuchHeaderException;
044import org.apache.camel.Processor;
045
046/**
047 * Converts a Fedora Message into a format suitable for a LDN receiver.
048 * See: http://www.w3.org/TR/ldn/
049 *
050 * @author acoburn
051 */
052public class LdnProcessor implements Processor {
053
054    private static final String PROV = "http://www.w3.org/ns/prov#";
055
056    private static final Property wasAssociatedWith = createProperty(PROV + "wasAssociatedWith");
057    private static final Property wasAttributedTo = createProperty(PROV + "wasAttributedTo");
058    private static final Property wasGeneratedBy = createProperty(PROV + "wasGeneratedBy");
059    private static final Property used = createProperty(PROV + "used");
060
061    /**
062     * Process the Fedora message
063     *
064     * @param exchange the current camel message exchange
065     */
066    public void process(final Exchange exchange) throws IOException, NoSuchHeaderException {
067        final Message in = exchange.getIn();
068        final Model model = createDefaultModel();
069        final Model newModel = createDefaultModel();
070        final Resource resource = createResource(getSubjectUri(exchange));
071        final Resource event = createResource("");
072        final AtomicInteger counter = new AtomicInteger();
073        final ByteArrayOutputStream serializedGraph = new ByteArrayOutputStream();
074
075        read(model, in.getBody(InputStream.class),
076                contentTypeToLang(parse(in.getHeader(CONTENT_TYPE, String.class)).getMimeType()));
077
078        newModel.add(createStatement(event, used, resource));
079        model.listObjectsOfProperty(resource, wasGeneratedBy).forEachRemaining(obj -> {
080            if (obj.isResource()) {
081                obj.asResource().listProperties().forEachRemaining(stmt -> {
082                    newModel.add(createStatement(event, stmt.getPredicate(), stmt.getObject()));
083                });
084            }
085        });
086        model.listObjectsOfProperty(resource, wasAttributedTo).forEachRemaining(obj -> {
087            final Resource agent = createResource("#agent" + Integer.toString(counter.getAndIncrement()));
088            if (obj.isResource()) {
089                obj.asResource().listProperties().forEachRemaining(stmt -> {
090                    newModel.add(createStatement(agent, stmt.getPredicate(), stmt.getObject()));
091                });
092            }
093            newModel.add(createStatement(event, wasAssociatedWith, agent));
094        });
095
096        write(serializedGraph, newModel, JSONLD);
097        in.setBody(serializedGraph.toString("UTF-8"));
098        in.setHeader(HTTP_METHOD, "POST");
099        in.setHeader(CONTENT_TYPE, "application/ld+json");
100    }
101}