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.kernel.modeshape.rdf.impl;
019
020import static org.fcrepo.kernel.modeshape.identifiers.NodeResourceConverter.nodeConverter;
021import static org.fcrepo.kernel.modeshape.rdf.converters.ValueConverter.nodeForValue;
022import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.getJcrNode;
023import static org.fcrepo.kernel.modeshape.utils.StreamUtils.iteratorToStream;
024import static org.fcrepo.kernel.modeshape.utils.UncheckedFunction.uncheck;
025import static java.util.Arrays.asList;
026import static javax.jcr.PropertyType.PATH;
027import static javax.jcr.PropertyType.REFERENCE;
028import static javax.jcr.PropertyType.WEAKREFERENCE;
029
030import org.apache.jena.graph.Triple;
031import org.apache.jena.rdf.model.Resource;
032import org.fcrepo.kernel.api.identifiers.IdentifierConverter;
033import org.fcrepo.kernel.api.models.FedoraResource;
034import org.fcrepo.kernel.modeshape.rdf.impl.mappings.PropertyToTriple;
035import org.fcrepo.kernel.modeshape.rdf.impl.mappings.PropertyValueIterator;
036
037import javax.jcr.Node;
038import javax.jcr.Property;
039import javax.jcr.RepositoryException;
040import javax.jcr.Value;
041
042import java.util.List;
043import java.util.function.Predicate;
044import java.util.stream.Stream;
045
046/**
047 * Accumulate inbound references to a given resource
048 *
049 * @author cabeer
050 * @author escowles
051 */
052public class ReferencesRdfContext extends NodeRdfContext {
053
054    private final PropertyToTriple property2triple;
055
056    public static final List<Integer> REFERENCE_TYPES = asList(PATH, REFERENCE, WEAKREFERENCE);
057
058    /**
059     * Add the inbound references from other nodes to this resource to the stream
060     *
061     * @param resource the resource
062     * @param idTranslator the id translator
063     * @throws RepositoryException if repository exception occurred
064     */
065
066    public ReferencesRdfContext(final FedoraResource resource,
067                                final IdentifierConverter<Resource, FedoraResource> idTranslator)
068        throws RepositoryException {
069        super(resource, idTranslator);
070        property2triple = new PropertyToTriple(getJcrNode(resource).getSession(), idTranslator);
071        concat(putReferencesIntoContext(getJcrNode(resource)));
072    }
073
074    private final Predicate<Triple> INBOUND = t -> {
075        return t.getObject().getURI().equals(uriFor(resource()).getURI());
076    };
077
078    /* References from LDP indirect containers are generated dynamically by LdpContainerRdfContext, so they won't
079       show up in getReferences()/getWeakReferences().  Instead, we should check referencers to see if they are
080       members of an IndirectContainer and generate the appropriate inbound references. */
081    private Stream<Triple> putReferencesIntoContext(final Node node) throws RepositoryException {
082        return Stream.concat(
083            getAllReferences(node).flatMap(property2triple),
084            getAllReferences(node).flatMap(uncheck((final Property x) -> {
085                    @SuppressWarnings("unchecked")
086                    final Stream<Value> values = iteratorToStream(new PropertyValueIterator(x.getParent()
087                            .getProperties())).filter((final Value y) -> REFERENCE_TYPES.contains(y.getType()));
088                    return values;
089                }))
090                .flatMap(uncheck((final Value x) -> {
091                    return new LdpContainerRdfContext(nodeConverter.convert(nodeForValue(node.getSession(), x)),
092                        translator());
093                }))
094                .filter(INBOUND));
095    }
096
097    @SuppressWarnings("unchecked")
098    private static Stream<Property> getAllReferences(final Node node) throws RepositoryException {
099        return Stream.concat(iteratorToStream(node.getReferences()), iteratorToStream(node.getWeakReferences()));
100    }
101}