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.impl.rdf.impl;
017
018import com.google.common.base.Function;
019import com.google.common.base.Predicate;
020import com.google.common.collect.Iterators;
021import com.hp.hpl.jena.graph.Triple;
022import com.hp.hpl.jena.rdf.model.RDFNode;
023import com.hp.hpl.jena.rdf.model.Resource;
024
025import org.fcrepo.kernel.models.NonRdfSourceDescription;
026import org.fcrepo.kernel.models.FedoraResource;
027import org.fcrepo.kernel.exception.RepositoryRuntimeException;
028import org.fcrepo.kernel.identifiers.IdentifierConverter;
029import org.fcrepo.kernel.impl.rdf.converters.ValueConverter;
030import org.fcrepo.kernel.impl.rdf.impl.mappings.PropertyValueIterator;
031
032import org.slf4j.Logger;
033
034import javax.jcr.Node;
035import javax.jcr.Property;
036import javax.jcr.RepositoryException;
037import javax.jcr.Value;
038
039import java.util.Iterator;
040
041import static com.google.common.collect.Iterators.singletonIterator;
042import static com.hp.hpl.jena.graph.NodeFactory.createURI;
043import static com.hp.hpl.jena.graph.Triple.create;
044import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
045import static java.util.Collections.emptyIterator;
046import static org.fcrepo.kernel.FedoraJcrTypes.LDP_BASIC_CONTAINER;
047import static org.fcrepo.kernel.FedoraJcrTypes.LDP_DIRECT_CONTAINER;
048import static org.fcrepo.kernel.FedoraJcrTypes.LDP_HAS_MEMBER_RELATION;
049import static org.fcrepo.kernel.FedoraJcrTypes.LDP_INDIRECT_CONTAINER;
050import static org.fcrepo.kernel.FedoraJcrTypes.LDP_INSERTED_CONTENT_RELATION;
051import static org.fcrepo.kernel.FedoraJcrTypes.LDP_MEMBER_RESOURCE;
052import static org.fcrepo.kernel.RdfLexicon.LDP_MEMBER;
053import static org.fcrepo.kernel.RdfLexicon.MEMBER_SUBJECT;
054import static org.fcrepo.kernel.impl.identifiers.NodeResourceConverter.nodeConverter;
055import static org.fcrepo.kernel.impl.rdf.converters.PropertyConverter.getPropertyNameFromPredicate;
056import static org.slf4j.LoggerFactory.getLogger;
057
058/**
059 * @author cabeer
060 * @author ajs6f
061 * @since 9/25/14
062 */
063public class LdpContainerRdfContext extends NodeRdfContext {
064    private static final Logger LOGGER = getLogger(ChildrenRdfContext.class);
065
066    /**
067     * Default constructor.
068     *
069     * @param resource
070     * @param idTranslator
071     * @throws javax.jcr.RepositoryException
072     */
073    public LdpContainerRdfContext(final FedoraResource resource,
074                                  final IdentifierConverter<Resource, FedoraResource> idTranslator)
075            throws RepositoryException {
076        super(resource, idTranslator);
077        final Iterator<Property> memberReferences = resource.getNode().getReferences(LDP_MEMBER_RESOURCE);
078        final Iterator<Property> properties = Iterators.filter(memberReferences, isContainer );
079
080        if (properties.hasNext()) {
081            LOGGER.trace("Found membership containers for {}", resource);
082            concat(membershipContext(properties));
083        }
084    }
085
086    private static Predicate<Property> isContainer = new Predicate<Property>() {
087
088        @Override
089        public boolean apply(final Property property) {
090            try {
091                final Node container = property.getParent();
092                return container.isNodeType(LDP_DIRECT_CONTAINER) || container.isNodeType(LDP_INDIRECT_CONTAINER);
093            } catch (final RepositoryException e) {
094                throw new RepositoryRuntimeException(e);
095            }
096        }
097    };
098
099    private Iterator<Triple> membershipContext(final Iterator<Property> properties) {
100        return Iterators.concat(Iterators.transform(properties, nodes2triples()));
101    }
102
103    private Function<Property, Iterator<Triple>> nodes2triples() {
104        return new Function<Property,Iterator<Triple>>() {
105
106            @Override
107            public Iterator<Triple> apply(final Property property) {
108                try {
109                    final FedoraResource resource = nodeConverter.convert(property.getParent());
110                    return memberRelations(resource);
111                } catch (final RepositoryException e) {
112                    throw new RepositoryRuntimeException(e);
113                }
114            }
115        };
116    }
117
118    /**
119     * Get the member relations assert on the subject by the given node
120     * @param container
121     * @return
122     * @throws RepositoryException
123     */
124    private Iterator<Triple> memberRelations(final FedoraResource container) throws RepositoryException {
125        final com.hp.hpl.jena.graph.Node memberRelation;
126
127        if (container.hasProperty(LDP_HAS_MEMBER_RELATION)) {
128            final Property property = container.getProperty(LDP_HAS_MEMBER_RELATION);
129            memberRelation = createURI(property.getString());
130        } else if (container.hasType(LDP_BASIC_CONTAINER)) {
131            memberRelation = LDP_MEMBER.asNode();
132        } else {
133            return emptyIterator();
134        }
135
136        final String insertedContainerProperty;
137
138        if (container.hasType(LDP_INDIRECT_CONTAINER)) {
139            if (container.hasProperty(LDP_INSERTED_CONTENT_RELATION)) {
140                insertedContainerProperty = container.getProperty(LDP_INSERTED_CONTENT_RELATION).getString();
141            } else {
142                return emptyIterator();
143            }
144        } else {
145            insertedContainerProperty = MEMBER_SUBJECT.getURI();
146        }
147
148        final Iterator<FedoraResource> memberNodes = container.getChildren();
149
150        return Iterators.concat(Iterators.transform(memberNodes, new Function<FedoraResource, Iterator<Triple>>() {
151            @Override
152            public Iterator<Triple> apply(final FedoraResource child) {
153
154                try {
155                    final com.hp.hpl.jena.graph.Node childSubject;
156                    if (child instanceof NonRdfSourceDescription) {
157                        childSubject = translator().reverse()
158                                .convert(((NonRdfSourceDescription) child).getDescribedResource())
159                                .asNode();
160                    } else {
161                        childSubject = translator().reverse().convert(child).asNode();
162                    }
163
164                    if (insertedContainerProperty.equals(MEMBER_SUBJECT.getURI())) {
165
166                        return singletonIterator(create(subject(), memberRelation, childSubject));
167                    }
168                    final String insertedContentProperty = getPropertyNameFromPredicate(resource().getNode(),
169                            createResource(insertedContainerProperty),
170                            null);
171
172                    if (!child.hasProperty(insertedContentProperty)) {
173                        return emptyIterator();
174                    }
175
176                    final PropertyValueIterator values
177                            = new PropertyValueIterator(child.getProperty(insertedContentProperty));
178
179                    return Iterators.transform(values, new Function<Value, Triple>() {
180                        @Override
181                        public Triple apply(final Value input) {
182                            final RDFNode membershipResource = new ValueConverter(session(), translator())
183                                    .convert(input);
184                            return create(subject(), memberRelation, membershipResource.asNode());
185                        }
186                    });
187                } catch (final RepositoryException e) {
188                    throw new RepositoryRuntimeException(e);
189                }
190            }
191        }));
192    }
193}