001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.kernel.modeshape.rdf.impl.mappings;
019
020import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDstring;
021import static com.hp.hpl.jena.graph.NodeFactory.createLiteral;
022import static com.hp.hpl.jena.graph.Triple.create;
023import static org.fcrepo.kernel.modeshape.identifiers.NodeResourceConverter.nodeToResource;
024import static org.fcrepo.kernel.modeshape.utils.StreamUtils.iteratorToStream;
025
026import java.util.function.Function;
027import java.util.stream.Stream;
028
029import javax.jcr.Node;
030import javax.jcr.Property;
031import javax.jcr.RepositoryException;
032import javax.jcr.Session;
033import com.google.common.base.Converter;
034import com.hp.hpl.jena.graph.impl.LiteralLabel;
035import com.hp.hpl.jena.rdf.model.Resource;
036
037import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
038import org.fcrepo.kernel.api.models.FedoraResource;
039import org.fcrepo.kernel.modeshape.rdf.converters.PropertyConverter;
040import org.fcrepo.kernel.modeshape.rdf.converters.ValueConverter;
041import com.hp.hpl.jena.datatypes.RDFDatatype;
042import com.hp.hpl.jena.graph.Triple;
043
044/**
045 * Utility for moving from JCR properties to RDF triples.
046 *
047 * @author ajs6f
048 * @since Oct 10, 2013
049 */
050public class PropertyToTriple implements Function<Property, Stream<Triple>> {
051
052    private static final PropertyConverter propertyConverter = new PropertyConverter();
053    private final ValueConverter valueConverter;
054    private final Converter<Node, Resource> translator;
055
056    /**
057     * Default constructor. We require a {@link Converter} in order to construct the RDF subjects of our triples.
058     *
059     * @param converter a converter between RDF and the Fedora model
060     * @param session the JCR session
061     */
062    public PropertyToTriple(final Session session, final Converter<Resource, FedoraResource> converter) {
063        this.valueConverter = new ValueConverter(session, converter);
064        this.translator = nodeToResource(converter);
065    }
066
067    @Override
068    public Stream<Triple> apply(final Property p) {
069        try {
070            final com.hp.hpl.jena.graph.Node subject = translator.convert(p.getParent()).asNode();
071            final com.hp.hpl.jena.graph.Node propPredicate = propertyConverter.convert(p).asNode();
072            final String propertyName = p.getName();
073
074            return iteratorToStream(new PropertyValueIterator(p)).map(v -> {
075                final com.hp.hpl.jena.graph.Node object = valueConverter.convert(v).asNode();
076                if (object.isLiteral()) {
077                    // unpack the name of the property for information about what kind of literal
078                    final int i = propertyName.indexOf('@');
079                    if (i > 0) {
080                        final LiteralLabel literal = object.getLiteral();
081                        final RDFDatatype datatype = literal.getDatatype();
082                        final String datatypeURI = datatype.getURI();
083                        if (datatypeURI.isEmpty() || datatype.equals(XSDstring)) {
084                            // this is an RDF string literal and could involve an RDF lang tag
085                            final String lang = propertyName.substring(i + 1);
086                            final String lex = literal.getLexicalForm();
087                            return create(subject, propPredicate, createLiteral(lex, lang, datatype));
088                        }
089                    }
090                }
091                return create(subject, propPredicate, object);
092            });
093        } catch (final RepositoryException e) {
094            throw new RepositoryRuntimeException(e);
095        }
096    }
097}