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