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