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 com.google.common.collect.Iterators;
019import com.hp.hpl.jena.graph.Triple;
020import com.hp.hpl.jena.rdf.model.Resource;
021
022import org.fcrepo.kernel.api.models.NonRdfSourceDescription;
023import org.fcrepo.kernel.api.utils.UncheckedFunction;
024import org.fcrepo.kernel.api.utils.UncheckedPredicate;
025import org.fcrepo.kernel.api.models.FedoraResource;
026import org.fcrepo.kernel.api.identifiers.IdentifierConverter;
027import org.fcrepo.kernel.modeshape.rdf.converters.ValueConverter;
028import org.fcrepo.kernel.modeshape.rdf.impl.mappings.PropertyValueIterator;
029
030import org.slf4j.Logger;
031
032import javax.jcr.Node;
033import javax.jcr.Property;
034import javax.jcr.RepositoryException;
035import java.util.Iterator;
036import static com.google.common.collect.Iterators.singletonIterator;
037import static com.hp.hpl.jena.graph.NodeFactory.createURI;
038import static com.hp.hpl.jena.graph.Triple.create;
039import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
040import static java.util.Collections.emptyIterator;
041import static org.fcrepo.kernel.api.FedoraJcrTypes.LDP_BASIC_CONTAINER;
042import static org.fcrepo.kernel.api.FedoraJcrTypes.LDP_DIRECT_CONTAINER;
043import static org.fcrepo.kernel.api.FedoraJcrTypes.LDP_HAS_MEMBER_RELATION;
044import static org.fcrepo.kernel.api.FedoraJcrTypes.LDP_INDIRECT_CONTAINER;
045import static org.fcrepo.kernel.api.FedoraJcrTypes.LDP_INSERTED_CONTENT_RELATION;
046import static org.fcrepo.kernel.api.FedoraJcrTypes.LDP_MEMBER_RESOURCE;
047import static org.fcrepo.kernel.api.RdfLexicon.LDP_MEMBER;
048import static org.fcrepo.kernel.api.RdfLexicon.MEMBER_SUBJECT;
049import static org.fcrepo.kernel.api.utils.UncheckedFunction.uncheck;
050import static org.fcrepo.kernel.modeshape.identifiers.NodeResourceConverter.nodeConverter;
051import static org.fcrepo.kernel.modeshape.rdf.converters.PropertyConverter.getPropertyNameFromPredicate;
052import static org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils.getReferencePropertyName;
053import static org.slf4j.LoggerFactory.getLogger;
054
055/**
056 * @author cabeer
057 * @author ajs6f
058 * @since 9/25/14
059 */
060public class LdpContainerRdfContext extends NodeRdfContext {
061    private static final Logger LOGGER = getLogger(ChildrenRdfContext.class);
062
063    /**
064     * Default constructor.
065     *
066     * @param resource the resource
067     * @param idTranslator the id translator
068     * @throws javax.jcr.RepositoryException if repository exception occurred
069     */
070    public LdpContainerRdfContext(final FedoraResource resource,
071                                  final IdentifierConverter<Resource, FedoraResource> idTranslator)
072            throws RepositoryException {
073        super(resource, idTranslator);
074        @SuppressWarnings("unchecked")
075        final Iterator<Property> memberReferences = resource.getNode().getReferences(LDP_MEMBER_RESOURCE);
076        final Iterator<Property> properties = Iterators.filter(memberReferences, UncheckedPredicate.uncheck(
077                    (final Property p) -> {
078                        final Node container = p.getParent();
079                        return container.isNodeType(LDP_DIRECT_CONTAINER)
080                            || container.isNodeType(LDP_INDIRECT_CONTAINER);
081                    })::test);
082
083        if (properties.hasNext()) {
084            LOGGER.trace("Found membership containers for {}", resource);
085            concat(membershipContext(properties));
086        }
087    }
088
089    private Iterator<Triple> membershipContext(final Iterator<Property> properties) {
090        return flatMap(properties, uncheck(p -> memberRelations(nodeConverter.convert(p.getParent()))));
091    }
092
093    /**
094     * Get the member relations assert on the subject by the given node
095     * @param container
096     * @return
097     * @throws RepositoryException
098     */
099    private Iterator<Triple> memberRelations(final FedoraResource container) throws RepositoryException {
100        final com.hp.hpl.jena.graph.Node memberRelation;
101
102        if (container.hasProperty(LDP_HAS_MEMBER_RELATION)) {
103            final Property property = container.getProperty(LDP_HAS_MEMBER_RELATION);
104            memberRelation = createURI(property.getString());
105        } else if (container.hasType(LDP_BASIC_CONTAINER)) {
106            memberRelation = LDP_MEMBER.asNode();
107        } else {
108            return emptyIterator();
109        }
110
111        final String insertedContainerProperty;
112
113        if (container.hasType(LDP_INDIRECT_CONTAINER)) {
114            if (container.hasProperty(LDP_INSERTED_CONTENT_RELATION)) {
115                insertedContainerProperty = container.getProperty(LDP_INSERTED_CONTENT_RELATION).getString();
116            } else {
117                return emptyIterator();
118            }
119        } else {
120            insertedContainerProperty = MEMBER_SUBJECT.getURI();
121        }
122
123        return flatMap(container.getChildren(),
124                UncheckedFunction.<FedoraResource, Iterator<Triple>>uncheck(child -> {
125                    final com.hp.hpl.jena.graph.Node childSubject = child instanceof NonRdfSourceDescription
126                            ? uriFor(((NonRdfSourceDescription) child).getDescribedResource()) : uriFor(child);
127
128                    if (insertedContainerProperty.equals(MEMBER_SUBJECT.getURI())) {
129                        return singletonIterator(create(subject(), memberRelation, childSubject));
130                    }
131                    String insertedContentProperty = getPropertyNameFromPredicate(resource().getNode(),
132                            createResource(insertedContainerProperty), null);
133
134                    if (child.hasProperty(insertedContentProperty)) {
135                        // do nothing, insertedContentProperty is good
136
137                    } else if (child.hasProperty(getReferencePropertyName(insertedContentProperty))) {
138                        // The insertedContentProperty is a pseudo reference property
139                        insertedContentProperty = getReferencePropertyName(insertedContentProperty);
140
141                    } else {
142                        // No property found!
143                        return emptyIterator();
144                    }
145
146                    final PropertyValueIterator values =
147                            new PropertyValueIterator(child.getProperty(insertedContentProperty));
148
149                    return Iterators.transform(values, v -> create(subject(), memberRelation,
150                            new ValueConverter(session(), translator()).convert(v).asNode()));
151
152                }));
153    }
154}