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