001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.jena; 014 015import java.util.*; 016import java.util.concurrent.*; 017 018import org.apache.juneau.*; 019import org.apache.juneau.annotation.*; 020import org.apache.juneau.collections.*; 021import org.apache.juneau.parser.*; 022import org.apache.juneau.xml.*; 023 024/** 025 * Parses RDF into POJOs. 026 * 027 * <h5 class='topic'>Behavior-specific subclasses</h5> 028 * 029 * The following direct subclasses are provided for language-specific parsers: 030 * <ul class='spaced-list'> 031 * <li> 032 * {@link RdfXmlParser} - RDF/XML and RDF/XML-ABBREV. 033 * <li> 034 * {@link NTripleParser} - N-TRIPLE. 035 * <li> 036 * {@link TurtleParser} - TURTLE. 037 * <li> 038 * {@link N3Parser} - N3. 039 * </ul> 040 * 041 * <ul class='seealso'> 042 * <li class='link'>{@doc juneau-marshall-rdf} 043 * </ul> 044 */ 045@ConfigurableContext(prefixes={RdfCommon.PREFIX,RdfParser.PREFIX}) 046public class RdfParser extends ReaderParser implements RdfCommon, RdfMetaProvider { 047 048 private static final Namespace 049 DEFAULT_JUNEAU_NS = Namespace.create("j", "http://www.apache.org/juneau/"), 050 DEFAULT_JUNEAUBP_NS = Namespace.create("jp", "http://www.apache.org/juneaubp/"); 051 052 //------------------------------------------------------------------------------------------------------------------- 053 // Configurable properties 054 //------------------------------------------------------------------------------------------------------------------- 055 056 static final String PREFIX = "RdfParser"; 057 058 /** 059 * Configuration property: Trim whitespace from text elements. 060 * 061 * <h5 class='section'>Property:</h5> 062 * <ul class='spaced-list'> 063 * <li><b>ID:</b> {@link org.apache.juneau.jena.RdfParser#RDF_trimWhitespace RDF_trimWhitespace} 064 * <li><b>Name:</b> <js>"RdfParser.trimWhitespace.b"</js> 065 * <li><b>Data type:</b> <jk>boolean</jk> 066 * <li><b>System property:</b> <c>RdfParser.trimWhitespace</c> 067 * <li><b>Environment variable:</b> <c>RDFPARSER_TRIMWHITESPACE</c> 068 * <li><b>Default:</b> <jk>false</jk> 069 * <li><b>Session property:</b> <jk>false</jk> 070 * <li><b>Annotations:</b> 071 * <ul> 072 * <li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig#trimWhitespace()} 073 * </ul> 074 * <li><b>Methods:</b> 075 * <ul> 076 * <li class='jm'>{@link org.apache.juneau.jena.RdfParserBuilder#trimWhitespace(boolean)} 077 * <li class='jm'>{@link org.apache.juneau.jena.RdfParserBuilder#trimWhitespace()} 078 * </ul> 079 * </ul> 080 * 081 * <h5 class='section'>Description:</h5> 082 * <p> 083 * If <jk>true</jk>, whitespace in text elements will be automatically trimmed. 084 * 085 * <h5 class='section'>Example:</h5> 086 * <p class='bcode w800'> 087 * <jc>// Create an RDF parser that trims whitespace.</jc> 088 * ReaderParser p = RdfParser 089 * .<jsm>create</jsm>() 090 * .xml() 091 * .trimWhitespace() 092 * .build(); 093 * 094 * <jc>// Same, but use property.</jc> 095 * ReaderParser p = RdfParser 096 * .<jsm>create</jsm>() 097 * .xml() 098 * .set(<jsf>RDF_trimWhitespace</jsf>, <jk>true</jk>) 099 * .build(); 100 * </p> 101 */ 102 public static final String RDF_trimWhitespace = PREFIX + ".trimWhitespace.b"; 103 104 //------------------------------------------------------------------------------------------------------------------- 105 // Instance 106 //------------------------------------------------------------------------------------------------------------------- 107 108 private final boolean trimWhitespace, looseCollections; 109 private final String rdfLanguage; 110 private final Namespace juneauNs, juneauBpNs; 111 private final RdfCollectionFormat collectionFormat; 112 113 final Map<String,Object> jenaProperties; 114 115 private final Map<ClassMeta<?>,RdfClassMeta> rdfClassMetas = new ConcurrentHashMap<>(); 116 private final Map<BeanMeta<?>,RdfBeanMeta> rdfBeanMetas = new ConcurrentHashMap<>(); 117 private final Map<BeanPropertyMeta,RdfBeanPropertyMeta> rdfBeanPropertyMetas = new ConcurrentHashMap<>(); 118 119 private final Map<ClassMeta<?>,XmlClassMeta> xmlClassMetas = new ConcurrentHashMap<>(); 120 private final Map<BeanMeta<?>,XmlBeanMeta> xmlBeanMetas = new ConcurrentHashMap<>(); 121 private final Map<BeanPropertyMeta,XmlBeanPropertyMeta> xmlBeanPropertyMetas = new ConcurrentHashMap<>(); 122 123 /** 124 * Constructor. 125 * 126 * @param ps The property store containing all the settings for this object. 127 * @param consumes The list of media types that this parser consumes (e.g. <js>"application/json"</js>). 128 */ 129 public RdfParser(PropertyStore ps, String...consumes) { 130 super(ps, consumes); 131 trimWhitespace = getBooleanProperty(RDF_trimWhitespace, false); 132 looseCollections = getBooleanProperty(RDF_looseCollections, false); 133 rdfLanguage = getStringProperty(RDF_language, "RDF/XML-ABBREV"); 134 juneauNs = getInstanceProperty(RDF_juneauNs, Namespace.class, DEFAULT_JUNEAU_NS); 135 juneauBpNs = getInstanceProperty(RDF_juneauBpNs, Namespace.class, DEFAULT_JUNEAUBP_NS); 136 collectionFormat = getProperty(RDF_collectionFormat, RdfCollectionFormat.class, RdfCollectionFormat.DEFAULT); 137 138 ASortedMap<String,Object> m = ASortedMap.of(); 139 for (String k : getPropertyKeys("RdfCommon")) 140 if (k.startsWith("jena.")) 141 m.put(k.substring(5), getProperty("RdfCommon." + k)); 142 jenaProperties = m.unmodifiable(); 143 } 144 145 /** 146 * Constructor. 147 * 148 * @param ps The property store containing all the settings for this object. 149 */ 150 public RdfParser(PropertyStore ps) { 151 this(ps, getConsumes(ps)); 152 } 153 154 private static String getConsumes(PropertyStore ps) { 155 String rdfLanguage = ps.getProperty(RDF_language, String.class, "RDF/XML-ABBREV"); 156 switch(rdfLanguage) { 157 case "RDF/XML": 158 case "RDF/XML-ABBREV": return "text/xml+rdf"; 159 case "N-TRIPLE": return "text/n-triple"; 160 case "N3": return "text/n3"; 161 case "N3-PP": return "text/n3-pp"; 162 case "N3-PLAIN": return "text/n3-plain"; 163 case "N3-TRIPLES": return "text/n3-triples"; 164 case "TURTLE": return "text/turtle"; 165 default: return "text/xml+rdf"; 166 } 167 } 168 169 @Override /* Context */ 170 public RdfParserBuilder builder() { 171 return new RdfParserBuilder(getPropertyStore()); 172 } 173 174 /** 175 * Instantiates a new clean-slate {@link RdfParserBuilder} object. 176 * 177 * <p> 178 * This is equivalent to simply calling <code><jk>new</jk> RdfParserBuilder()</code>. 179 * 180 * <p> 181 * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies 182 * the settings of the object called on. 183 * 184 * @return A new {@link RdfParserBuilder} object. 185 */ 186 public static RdfParserBuilder create() { 187 return new RdfParserBuilder(); 188 } 189 190 @Override /* Parser */ 191 public RdfParserSession createSession() { 192 return createSession(createDefaultSessionArgs()); 193 } 194 195 @Override /* Parser */ 196 public RdfParserSession createSession(ParserSessionArgs args) { 197 return new RdfParserSession(this, args); 198 } 199 200 //----------------------------------------------------------------------------------------------------------------- 201 // Extended metadata 202 //----------------------------------------------------------------------------------------------------------------- 203 204 @Override /* RdfMetaProvider */ 205 public RdfClassMeta getRdfClassMeta(ClassMeta<?> cm) { 206 RdfClassMeta m = rdfClassMetas.get(cm); 207 if (m == null) { 208 m = new RdfClassMeta(cm, this); 209 rdfClassMetas.put(cm, m); 210 } 211 return m; 212 } 213 214 @Override /* RdfMetaProvider */ 215 public RdfBeanMeta getRdfBeanMeta(BeanMeta<?> bm) { 216 RdfBeanMeta m = rdfBeanMetas.get(bm); 217 if (m == null) { 218 m = new RdfBeanMeta(bm, this); 219 rdfBeanMetas.put(bm, m); 220 } 221 return m; 222 } 223 224 @Override /* RdfMetaProvider */ 225 public RdfBeanPropertyMeta getRdfBeanPropertyMeta(BeanPropertyMeta bpm) { 226 RdfBeanPropertyMeta m = rdfBeanPropertyMetas.get(bpm); 227 if (m == null) { 228 m = new RdfBeanPropertyMeta(bpm.getDelegateFor(), this); 229 rdfBeanPropertyMetas.put(bpm, m); 230 } 231 return m; 232 } 233 234 @Override /* XmlMetaProvider */ 235 public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) { 236 XmlClassMeta m = xmlClassMetas.get(cm); 237 if (m == null) { 238 m = new XmlClassMeta(cm, this); 239 xmlClassMetas.put(cm, m); 240 } 241 return m; 242 } 243 244 @Override /* XmlMetaProvider */ 245 public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) { 246 XmlBeanMeta m = xmlBeanMetas.get(bm); 247 if (m == null) { 248 m = new XmlBeanMeta(bm, this); 249 xmlBeanMetas.put(bm, m); 250 } 251 return m; 252 } 253 254 @Override /* XmlMetaProvider */ 255 public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) { 256 XmlBeanPropertyMeta m = xmlBeanPropertyMetas.get(bpm); 257 if (m == null) { 258 m = new XmlBeanPropertyMeta(bpm.getDelegateFor(), this); 259 xmlBeanPropertyMetas.put(bpm, m); 260 } 261 return m; 262 } 263 264 //----------------------------------------------------------------------------------------------------------------- 265 // Common properties 266 //----------------------------------------------------------------------------------------------------------------- 267 268 /** 269 * RDF format for representing collections and arrays. 270 * 271 * @see #RDF_collectionFormat 272 * @return 273 * RDF format for representing collections and arrays. 274 */ 275 protected final RdfCollectionFormat getCollectionFormat() { 276 return collectionFormat; 277 } 278 279 /** 280 * Default XML namespace for bean properties. 281 * 282 * @see #RDF_juneauBpNs 283 * @return 284 * Default XML namespace for bean properties. 285 */ 286 protected final Namespace getJuneauBpNs() { 287 return juneauBpNs; 288 } 289 290 /** 291 * XML namespace for Juneau properties. 292 * 293 * @see #RDF_juneauNs 294 * @return 295 * XML namespace for Juneau properties. 296 */ 297 protected final Namespace getJuneauNs() { 298 return juneauNs; 299 } 300 301 /** 302 * RDF language. 303 * 304 * @see #RDF_language 305 * @return 306 * The RDF language to use. 307 */ 308 protected final String getLanguage() { 309 return rdfLanguage; 310 } 311 312 /** 313 * Collections should be serialized and parsed as loose collections. 314 * 315 * @see #RDF_looseCollections 316 * @return 317 * <jk>true</jk> if collections of resources are handled as loose collections of resources in RDF instead of 318 * resources that are children of an RDF collection (e.g. Sequence, Bag). 319 */ 320 protected final boolean isLooseCollections() { 321 return looseCollections; 322 } 323 324 //----------------------------------------------------------------------------------------------------------------- 325 // Jena properties 326 //----------------------------------------------------------------------------------------------------------------- 327 328 /** 329 * All Jena-related configuration properties. 330 * 331 * @return 332 * A map of all Jena-related configuration properties. 333 */ 334 protected final Map<String,Object> getJenaProperties() { 335 return jenaProperties; 336 } 337 338 //----------------------------------------------------------------------------------------------------------------- 339 // Properties 340 //----------------------------------------------------------------------------------------------------------------- 341 342 /** 343 * Trim whitespace from text elements. 344 * 345 * @see #RDF_trimWhitespace 346 * @return 347 * <jk>true</jk> if whitespace in text elements will be automatically trimmed. 348 */ 349 protected final boolean isTrimWhitespace() { 350 return trimWhitespace; 351 } 352 353 //----------------------------------------------------------------------------------------------------------------- 354 // Other methods 355 //----------------------------------------------------------------------------------------------------------------- 356 357 @Override /* Context */ 358 public OMap toMap() { 359 return super.toMap() 360 .a("RdfParser", new DefaultFilteringOMap() 361 .a("trimWhitespace", trimWhitespace) 362 .a("looseCollections", looseCollections) 363 .a("rdfLanguage", rdfLanguage) 364 .a("juneauNs", juneauNs) 365 .a("juneauBpNs", juneauBpNs) 366 .a("collectionFormat", collectionFormat) 367 ); 368 } 369}