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