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.impl.rdf.converters; 017 018import com.google.common.base.Converter; 019import com.google.common.collect.ImmutableBiMap; 020import com.hp.hpl.jena.rdf.model.Property; 021import com.hp.hpl.jena.rdf.model.Resource; 022 023import org.fcrepo.kernel.exception.FedoraInvalidNamespaceException; 024import org.modeshape.jcr.api.NamespaceRegistry; 025import org.modeshape.jcr.api.Namespaced; 026import org.slf4j.Logger; 027 028import javax.jcr.Node; 029import javax.jcr.RepositoryException; 030 031import java.util.Map; 032 033import static com.google.common.base.Throwables.propagate; 034import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty; 035import static org.fcrepo.kernel.impl.rdf.JcrRdfTools.getJcrNamespaceForRDFNamespace; 036import static org.fcrepo.kernel.impl.rdf.JcrRdfTools.getRDFNamespaceForJcrNamespace; 037import static org.fcrepo.kernel.impl.utils.FedoraTypesUtils.getReferencePropertyOriginalName; 038import static org.fcrepo.kernel.impl.utils.FedoraTypesUtils.isInternalReferenceProperty; 039import static org.fcrepo.kernel.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.apply(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 propagate(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 final NamespaceRegistry namespaceRegistry = getNamespaceRegistry.apply(node); 098 return getPropertyNameFromPredicate(namespaceRegistry, 099 predicate, namespaceMapping); 100 } 101 102 /** 103 * Get the JCR property name for an RDF predicate 104 * 105 * @param namespaceRegistry the namespace registry 106 * @param predicate the predicate to map to a property name 107 * @param namespaceMapping the namespace mapping 108 * @return JCR property name for an RDF predicate 109 * @throws RepositoryException if repository exception occurred 110 */ 111 public static String getPropertyNameFromPredicate(final NamespaceRegistry namespaceRegistry, 112 final Resource predicate, 113 final Map<String, String> namespaceMapping) 114 throws RepositoryException { 115 116 // reject if update request contains any fcr namespaces 117 if (namespaceMapping != null && namespaceMapping.containsKey("fcr")) { 118 throw new FedoraInvalidNamespaceException("Invalid fcr namespace properties " + predicate + "."); 119 } 120 121 final String rdfNamespace = predicate.getNameSpace(); 122 123 // log warning if the user-supplied namespace doesn't match value from predicate.getNameSpace(), 124 // e.g., if the Jena method returns "http://" for "http://myurl.org" (no terminating character). 125 if (namespaceMapping != null && !namespaceMapping.containsValue(rdfNamespace)) { 126 LOGGER.warn("The namespace of predicate: {} was possibly misinterpreted as: {}." 127 , predicate, rdfNamespace); 128 } 129 130 final String rdfLocalname = predicate.getLocalName(); 131 132 final String prefix; 133 134 assert (namespaceRegistry != null); 135 136 final String namespace = getJcrNamespaceForRDFNamespace(rdfNamespace); 137 138 if (namespaceRegistry.isRegisteredUri(namespace)) { 139 LOGGER.debug("Discovered namespace: {} in namespace registry.",namespace); 140 prefix = namespaceRegistry.getPrefix(namespace); 141 } else { 142 LOGGER.debug("Didn't discover namespace: {} in namespace registry.",namespace); 143 final ImmutableBiMap<String, String> nsMap = 144 ImmutableBiMap.copyOf(namespaceMapping); 145 if (nsMap.containsValue(namespace)) { 146 LOGGER.debug("Discovered namespace: {} in namespace map: {}.", namespace, 147 nsMap); 148 prefix = nsMap.inverse().get(namespace); 149 namespaceRegistry.registerNamespace(prefix, namespace); 150 } else { 151 prefix = namespaceRegistry.registerNamespace(namespace); 152 } 153 } 154 155 final String propertyName = prefix + ":" + rdfLocalname; 156 157 LOGGER.debug("Took RDF predicate {} and translated it to JCR property {}", namespace, propertyName); 158 159 return propertyName; 160 161 } 162 163}