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.mappings;
017
018import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDstring;
019import static com.hp.hpl.jena.graph.NodeFactory.createLiteral;
020import static com.hp.hpl.jena.graph.Triple.create;
021import static org.fcrepo.kernel.modeshape.identifiers.NodeResourceConverter.nodeToResource;
022import static org.fcrepo.kernel.modeshape.utils.StreamUtils.iteratorToStream;
023
024import java.util.function.Function;
025import java.util.stream.Stream;
026
027import javax.jcr.Node;
028import javax.jcr.Property;
029import javax.jcr.RepositoryException;
030import javax.jcr.Session;
031import com.google.common.base.Converter;
032import com.hp.hpl.jena.graph.impl.LiteralLabel;
033import com.hp.hpl.jena.rdf.model.Resource;
034
035import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
036import org.fcrepo.kernel.api.models.FedoraResource;
037import org.fcrepo.kernel.modeshape.rdf.converters.PropertyConverter;
038import org.fcrepo.kernel.modeshape.rdf.converters.ValueConverter;
039import com.hp.hpl.jena.datatypes.RDFDatatype;
040import com.hp.hpl.jena.graph.Triple;
041
042/**
043 * Utility for moving from JCR properties to RDF triples.
044 *
045 * @author ajs6f
046 * @since Oct 10, 2013
047 */
048public class PropertyToTriple implements Function<Property, Stream<Triple>> {
049
050    private static final PropertyConverter propertyConverter = new PropertyConverter();
051    private final ValueConverter valueConverter;
052    private final Converter<Node, Resource> translator;
053
054    /**
055     * Default constructor. We require a {@link Converter} in order to construct the RDF subjects of our triples.
056     *
057     * @param converter a converter between RDF and the Fedora model
058     * @param session the JCR session
059     */
060    public PropertyToTriple(final Session session, final Converter<Resource, FedoraResource> converter) {
061        this.valueConverter = new ValueConverter(session, converter);
062        this.translator = nodeToResource(converter);
063    }
064
065    @Override
066    public Stream<Triple> apply(final Property p) {
067        try {
068            final com.hp.hpl.jena.graph.Node subject = translator.convert(p.getParent()).asNode();
069            final com.hp.hpl.jena.graph.Node propPredicate = propertyConverter.convert(p).asNode();
070            final String propertyName = p.getName();
071
072            return iteratorToStream(new PropertyValueIterator(p)).map(v -> {
073                final com.hp.hpl.jena.graph.Node object = valueConverter.convert(v).asNode();
074                if (object.isLiteral()) {
075                    // unpack the name of the property for information about what kind of literal
076                    final int i = propertyName.indexOf('@');
077                    if (i > 0) {
078                        final LiteralLabel literal = object.getLiteral();
079                        final RDFDatatype datatype = literal.getDatatype();
080                        final String datatypeURI = datatype.getURI();
081                        if (datatypeURI.isEmpty() || datatype.equals(XSDstring)) {
082                            // this is an RDF string literal and could involve an RDF lang tag
083                            final String lang = propertyName.substring(i + 1);
084                            final String lex = literal.getLexicalForm();
085                            return create(subject, propPredicate, createLiteral(lex, lang, datatype));
086                        }
087                    }
088                }
089                return create(subject, propPredicate, object);
090            });
091        } catch (final RepositoryException e) {
092            throw new RepositoryRuntimeException(e);
093        }
094    }
095}