org.fcrepo.transform.transformations.LDPathTransform.java Source code

Java tutorial

Introduction

Here is the source code for org.fcrepo.transform.transformations.LDPathTransform.java

Source

/**
 * Copyright 2014 DuraSpace, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.fcrepo.transform.transformations;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;

import org.apache.marmotta.ldpath.LDPath;
import org.apache.marmotta.ldpath.backend.jena.GenericJenaBackend;
import org.apache.marmotta.ldpath.exception.LDPathParseException;
import org.fcrepo.transform.Transformation;
import org.slf4j.Logger;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.NodeType;
import javax.ws.rs.WebApplicationException;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.ImmutableSortedSet.orderedBy;
import static com.google.common.collect.Maps.transformValues;
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
import static org.apache.http.HttpStatus.SC_BAD_REQUEST;
import static org.fcrepo.kernel.rdf.SerializationUtils.getDatasetSubject;
import static org.fcrepo.kernel.rdf.SerializationUtils.unifyDatasetModel;
import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * Utilities for working with LDPath
 *
 * @author cbeer
 */
public class LDPathTransform implements Transformation<Map<String, Collection<Object>>> {

    public static final String CONFIGURATION_FOLDER = "/fedora:system/fedora:transform/fedora:ldpath/";

    // TODO: this mime type was made up
    public static final String APPLICATION_RDF_LDPATH = "application/rdf+ldpath";
    private final InputStream query;

    private static final Logger LOGGER = getLogger(LDPathTransform.class);

    private static final Comparator<NodeType> nodeTypeComp = new Comparator<NodeType>() {

        @Override
        public int compare(final NodeType o1, final NodeType o2) {
            return o1.getName().compareTo(o2.getName());

        }
    };

    /**
     * Construct a new Transform from the InputStream
     * @param query
     */
    public LDPathTransform(final InputStream query) {
        this.query = query;
    }

    /**
     * Pull a node-type specific transform out of JCR
     * @param node
     * @param key
     * @return
     * @throws RepositoryException
     */
    public static LDPathTransform getNodeTypeTransform(final Node node, final String key)
            throws RepositoryException {

        final Node programNode = node.getSession().getNode(CONFIGURATION_FOLDER + key);

        LOGGER.debug("Found program node: {}", programNode.getPath());

        final NodeType primaryNodeType = node.getPrimaryNodeType();

        final Set<NodeType> supertypes = orderedBy(nodeTypeComp).add(primaryNodeType.getSupertypes()).build();
        final Set<NodeType> mixinTypes = orderedBy(nodeTypeComp).add(node.getMixinNodeTypes()).build();

        // start with mixins, primary type, and supertypes of primary type
        final ImmutableList.Builder<NodeType> nodeTypesB = new ImmutableList.Builder<NodeType>().addAll(mixinTypes)
                .add(primaryNodeType).addAll(supertypes);

        // add supertypes of mixins
        for (final NodeType mixin : mixinTypes) {
            nodeTypesB.addAll(orderedBy(nodeTypeComp).add(mixin.getDeclaredSupertypes()).build());
        }

        final List<NodeType> nodeTypes = nodeTypesB.build();

        LOGGER.debug("Discovered node types: {}", nodeTypes);

        for (final NodeType nodeType : nodeTypes) {
            if (programNode.hasNode(nodeType.toString())) {
                return new LDPathTransform(programNode.getNode(nodeType.toString()).getNode(JCR_CONTENT)
                        .getProperty(JCR_DATA).getBinary().getStream());
            }
        }

        throw new WebApplicationException(
                new Exception(
                        "Couldn't find transformation for " + node.getPath() + " and transformation key " + key),
                SC_BAD_REQUEST);
    }

    @Override
    public Map<String, Collection<Object>> apply(final Dataset dataset) {
        try {
            final LDPath<RDFNode> ldpathForResource = getLdpathResource(dataset);

            final Resource context = createResource(getDatasetSubject(dataset).getURI());

            final Map<String, Collection<?>> wildcardCollection = ldpathForResource.programQuery(context,
                    new InputStreamReader(query));

            return transformLdpathOutputToSomethingSerializable(wildcardCollection);
        } catch (final LDPathParseException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public InputStream getQuery() {
        return query;
    }

    @Override
    public boolean equals(final Object other) {
        return other instanceof LDPathTransform && query.equals(((LDPathTransform) other).getQuery());
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getQuery());
    }

    /**
     * Get the LDPath resource for an object
     * @param dataset
     * @return
     */
    private static LDPath<RDFNode> getLdpathResource(final Dataset dataset) {

        return new LDPath<>(new GenericJenaBackend(unifyDatasetModel(dataset)));

    }

    /**
     * In order for the JAX-RS serialization magic to work, we have to turn the map into
     * a non-wildcard type.
     * @param collectionMap
     * @return
     */
    private static Map<String, Collection<Object>> transformLdpathOutputToSomethingSerializable(
            final Map<String, Collection<?>> collectionMap) {

        return transformValues(collectionMap, WILDCARD_COLLECTION_TO_OBJECT_COLLECTION);
    }

    private static final Function<Collection<?>, Collection<Object>> WILDCARD_COLLECTION_TO_OBJECT_COLLECTION = new Function<Collection<?>, Collection<Object>>() {

        @Override
        public Collection<Object> apply(final Collection<?> input) {
            return transform(input, ANYTHING_TO_OBJECT_FUNCTION);
        }
    };

    private static final Function<Object, Object> ANYTHING_TO_OBJECT_FUNCTION = new Function<Object, Object>() {

        @Override
        public Object apply(final Object input) {
            return input;
        }
    };

    @Override
    public LDPathTransform newTransform(final InputStream query) {
        return new LDPathTransform(query);
    }
}