001/**
002 * Copyright 2015 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.kernel.modeshape.rdf.impl;
017
018import static org.fcrepo.kernel.modeshape.identifiers.NodeResourceConverter.nodeConverter;
019import static org.fcrepo.kernel.modeshape.rdf.converters.ValueConverter.nodeForValue;
020import static javax.jcr.PropertyType.PATH;
021import static javax.jcr.PropertyType.REFERENCE;
022import static javax.jcr.PropertyType.WEAKREFERENCE;
023
024import com.google.common.base.Function;
025import com.google.common.base.Predicate;
026import com.google.common.collect.Iterators;
027import com.hp.hpl.jena.graph.Triple;
028import com.hp.hpl.jena.rdf.model.Resource;
029import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
030import org.fcrepo.kernel.api.identifiers.IdentifierConverter;
031import org.fcrepo.kernel.api.models.FedoraResource;
032import org.fcrepo.kernel.modeshape.rdf.impl.mappings.PropertyToTriple;
033import org.fcrepo.kernel.modeshape.rdf.impl.mappings.PropertyValueIterator;
034
035import javax.jcr.Node;
036import javax.jcr.Property;
037import javax.jcr.RepositoryException;
038import javax.jcr.Value;
039
040import java.util.Iterator;
041
042/**
043 * Accumulate inbound references to a given resource
044 *
045 * @author cabeer
046 * @author escowles
047 */
048public class ReferencesRdfContext extends NodeRdfContext {
049
050    private final PropertyToTriple property2triple;
051
052    /**
053     * Add the inbound references from other nodes to this resource to the stream
054     *
055     * @param resource the resource
056     * @param idTranslator the id translator
057     * @throws RepositoryException if repository exception occurred
058     */
059
060    public ReferencesRdfContext(final FedoraResource resource,
061                                final IdentifierConverter<Resource, FedoraResource> idTranslator)
062        throws RepositoryException {
063        super(resource, idTranslator);
064        property2triple = new PropertyToTriple(resource.getNode().getSession(), idTranslator);
065        putReferencesIntoContext(resource.getNode());
066    }
067
068    private void putReferencesIntoContext(final Node node) throws RepositoryException {
069        concat(Iterators.concat(Iterators.transform(
070            Iterators.concat(node.getReferences(), node.getWeakReferences()), property2triple)));
071        concat(Iterators.concat(Iterators.transform(Iterators.concat(Iterators.transform(
072            Iterators.concat(node.getReferences(), node.getWeakReferences()), potentialProxies)), triplesForValue)));
073    }
074
075    /* References from LDP indirect containers are generated dynamically by LdpContainerRdfContext, so they won't
076       show up in getReferences()/getWeakReferences().  Instead, we should check referrers to see if they are
077       members of an IndirectContainer and generate the appropriate inbound references. */
078    private Function<Property, Iterator<Value>> potentialProxies = new Function<Property, Iterator<Value>>() {
079        @Override
080        public Iterator<Value> apply(final Property p) {
081            try {
082                return Iterators.filter(new PropertyValueIterator(p.getParent().getProperties()), isReference);
083            } catch (RepositoryException ex) {
084                throw new RepositoryRuntimeException(ex);
085            }
086        }
087    };
088    private Function<Value, Iterator<Triple>> triplesForValue = new Function<Value, Iterator<Triple>>() {
089        @Override
090        public Iterator<Triple> apply(final Value v) {
091            try {
092                return new LdpContainerRdfContext(nodeConverter.convert(nodeForValue(session(), v)), translator());
093            } catch (RepositoryException ex) {
094                throw new RepositoryRuntimeException(ex);
095            }
096        }
097    };
098    private Predicate<Value> isReference = new Predicate<Value>() {
099        @Override
100        public boolean apply(final Value v) {
101            return v.getType() == PATH || v.getType() == REFERENCE || v.getType() == WEAKREFERENCE;
102        }
103    };
104
105}