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.google.common.base.Throwables.propagate; 019import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDanyURI; 020import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDboolean; 021import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDdate; 022import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDdecimal; 023import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDlong; 024import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDstring; 025import static com.hp.hpl.jena.graph.NodeFactory.createURI; 026import static com.hp.hpl.jena.graph.Triple.create; 027import static com.hp.hpl.jena.vocabulary.RDFS.range; 028import static java.util.stream.Stream.of; 029import static javax.jcr.PropertyType.BINARY; 030import static javax.jcr.PropertyType.BOOLEAN; 031import static javax.jcr.PropertyType.DATE; 032import static javax.jcr.PropertyType.DECIMAL; 033import static javax.jcr.PropertyType.DOUBLE; 034import static javax.jcr.PropertyType.LONG; 035import static javax.jcr.PropertyType.PATH; 036import static javax.jcr.PropertyType.REFERENCE; 037import static javax.jcr.PropertyType.STRING; 038import static javax.jcr.PropertyType.URI; 039import static javax.jcr.PropertyType.WEAKREFERENCE; 040import static javax.jcr.PropertyType.nameFromValue; 041import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE; 042import static org.slf4j.LoggerFactory.getLogger; 043 044import java.util.stream.Stream; 045import java.util.Map; 046 047import javax.jcr.RepositoryException; 048import javax.jcr.nodetype.PropertyDefinition; 049 050import org.slf4j.Logger; 051 052import com.google.common.collect.ImmutableMap; 053import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; 054import com.hp.hpl.jena.graph.Node; 055import com.hp.hpl.jena.graph.Triple; 056 057/** 058 * Utility for moving Property Definitions into RDFS triples 059 * @author cbeer 060 */ 061public class PropertyDefinitionToTriples extends ItemDefinitionToTriples<PropertyDefinition> { 062 063 private static final Logger LOGGER = getLogger(PropertyDefinitionToTriples.class); 064 065 /** 066 * A JCR type for which we know no RDF equivalent. 067 */ 068 private static final Node UNMAPPED_TYPE = createURI(REPOSITORY_NAMESPACE 069 + "UnmappedType"); 070 071 /** 072 * A map from JCR types to RDF types. 073 */ 074 private static final Map<Integer, XSDDatatype> JCR_TYPE_TO_XSD_DATATYPE = 075 ImmutableMap.<Integer, XSDDatatype>builder() 076 .put(BOOLEAN, XSDboolean) 077 .put(DATE, XSDdate) 078 .put(DECIMAL, XSDdecimal) 079 .put(DOUBLE, XSDdecimal) 080 .put(LONG, XSDlong) 081 .put(URI, XSDanyURI) 082 .put(REFERENCE, XSDanyURI) 083 .put(WEAKREFERENCE, XSDanyURI) 084 .put(PATH, XSDanyURI) 085 .put(BINARY, XSDstring) 086 .put(STRING, XSDstring).build(); 087 088 /** 089 * Translate ItemDefinitions into triples. The definitions will hang off 090 * the provided RDF Node 091 * @param domain the given domain 092 */ 093 public PropertyDefinitionToTriples(final Node domain) { 094 super(domain); 095 } 096 097 @Override 098 public Stream<Triple> apply(final PropertyDefinition input) { 099 100 if (!input.getName().contains(":")) { 101 LOGGER.debug("Received property definition with no namespace: {}", 102 input.getName()); 103 LOGGER.debug("This cannot be serialized into several RDF formats, " + 104 "so we assume it is internal and discard it."); 105 return Stream.empty(); 106 } 107 108 try { 109 // skip range declaration for unknown types 110 final int requiredType = input.getRequiredType(); 111 112 final Node rangeForJcrType = getRangeForJcrType(requiredType); 113 114 if (!rangeForJcrType.equals(UNMAPPED_TYPE)) { 115 LOGGER.trace("Adding RDFS:range for property: {} with required type: {} as: {}", 116 input.getName(), nameFromValue(requiredType), rangeForJcrType.getURI()); 117 final Triple propertyTriple = 118 create(getResource(input).asNode(), range.asNode(), 119 rangeForJcrType); 120 return Stream.concat(of(propertyTriple), super.apply(input)); 121 } 122 LOGGER.trace( 123 "Skipping RDFS:range for property: {} with unmappable type: {}", 124 input.getName(), nameFromValue(requiredType)); 125 return super.apply(input); 126 } catch (final RepositoryException e) { 127 throw propagate(e); 128 } 129 } 130 131 /** 132 * Convert a JCR type to an RDF data type. 133 * 134 * @param requiredType a JCR PropertyType 135 * @return rdf node of data type 136 */ 137 private static Node getRangeForJcrType(final int requiredType) { 138 return JCR_TYPE_TO_XSD_DATATYPE.containsKey(requiredType) 139 ? createURI(JCR_TYPE_TO_XSD_DATATYPE.get(requiredType).getURI()) 140 : UNMAPPED_TYPE; 141 } 142}