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