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.converters;
018
019import com.google.common.base.Converter;
020import com.google.common.collect.ImmutableBiMap;
021import com.hp.hpl.jena.rdf.model.Property;
022import com.hp.hpl.jena.rdf.model.Resource;
023import org.modeshape.jcr.api.NamespaceRegistry;
024import org.modeshape.jcr.api.Namespaced;
025import org.slf4j.Logger;
026
027import javax.jcr.Node;
028import javax.jcr.RepositoryException;
029
030import java.util.Map;
031
032import static com.google.common.base.Throwables.propagate;
033import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty;
034import static org.fcrepo.kernel.impl.rdf.JcrRdfTools.getJcrNamespaceForRDFNamespace;
035import static org.fcrepo.kernel.impl.rdf.JcrRdfTools.getRDFNamespaceForJcrNamespace;
036import static org.fcrepo.kernel.impl.utils.FedoraTypesUtils.getReferencePropertyOriginalName;
037import static org.fcrepo.kernel.impl.utils.FedoraTypesUtils.isInternalReferenceProperty;
038import static org.fcrepo.kernel.utils.NamespaceTools.getNamespaceRegistry;
039import static org.slf4j.LoggerFactory.getLogger;
040
041
042/**
043 * Convert between RDF properties and JCR properties
044 * @author cabeer
045 * @since 10/8/14
046 */
047public class PropertyConverter extends Converter<javax.jcr.Property, Property> {
048    private static final Logger LOGGER = getLogger(PropertyConverter.class);
049
050    @Override
051    protected Property doForward(final javax.jcr.Property property) {
052        LOGGER.trace("Creating predicate for property: {}",
053                property);
054        try {
055            if (property instanceof Namespaced) {
056                final Namespaced nsProperty = (Namespaced) property;
057                final String uri = nsProperty.getNamespaceURI();
058                final String localName = nsProperty.getLocalName();
059                final String rdfLocalName;
060
061                if (isInternalReferenceProperty.apply(property)) {
062                    rdfLocalName = getReferencePropertyOriginalName(localName);
063                } else {
064                    rdfLocalName = localName;
065                }
066                return createProperty(
067                        getRDFNamespaceForJcrNamespace(uri),
068                        rdfLocalName);
069            }
070            return createProperty(property.getName());
071        } catch (final RepositoryException e) {
072            throw propagate(e);
073        }
074
075    }
076
077    @Override
078    protected javax.jcr.Property doBackward(final Property property) {
079        throw new UnsupportedOperationException();
080    }
081
082    /**
083     * Given an RDF predicate value (namespace URI + local name), figure out
084     * what JCR property to use
085     *
086     * @param node the JCR node we want a property for
087     * @param predicate the predicate to map to a property name
088     * @param namespaceMapping prefix to uri namespace mapping
089     * @return the JCR property name
090     * @throws RepositoryException
091     */
092    public static String getPropertyNameFromPredicate(final Node node,
093                                                      final Resource predicate,
094                                                      final Map<String, String> namespaceMapping)
095            throws RepositoryException {
096        final NamespaceRegistry namespaceRegistry = getNamespaceRegistry.apply(node);
097        return getPropertyNameFromPredicate(namespaceRegistry,
098                predicate, namespaceMapping);
099    }
100
101    /**
102     * Get the JCR property name for an RDF predicate
103     *
104     * @param namespaceRegistry
105     * @param predicate the predicate to map to a property name
106     * @param namespaceMapping
107     * @return JCR property name for an RDF predicate
108     * @throws RepositoryException
109     */
110    public static String getPropertyNameFromPredicate(final NamespaceRegistry namespaceRegistry,
111                                                      final Resource predicate,
112                                                      final Map<String, String> namespaceMapping)
113            throws RepositoryException {
114
115        final String rdfNamespace = predicate.getNameSpace();
116        final String rdfLocalname = predicate.getLocalName();
117
118        final String prefix;
119
120        final String namespace = getJcrNamespaceForRDFNamespace(rdfNamespace);
121
122        assert (namespaceRegistry != null);
123
124        if (namespaceRegistry.isRegisteredUri(namespace)) {
125            LOGGER.debug("Discovered namespace: {} in namespace registry.",namespace);
126            prefix = namespaceRegistry.getPrefix(namespace);
127        } else {
128            LOGGER.debug("Didn't discover namespace: {} in namespace registry.",namespace);
129            final ImmutableBiMap<String, String> nsMap =
130                    ImmutableBiMap.copyOf(namespaceMapping);
131            if (nsMap.containsValue(namespace)) {
132                LOGGER.debug("Discovered namespace: {} in namespace map: {}.", namespace,
133                        nsMap);
134                prefix = nsMap.inverse().get(namespace);
135                namespaceRegistry.registerNamespace(prefix, namespace);
136            } else {
137                prefix = namespaceRegistry.registerNamespace(namespace);
138            }
139        }
140
141        final String propertyName = prefix + ":" + rdfLocalname;
142
143        LOGGER.debug("Took RDF predicate {} and translated it to JCR property {}", namespace, propertyName);
144
145        return propertyName;
146
147    }
148
149}