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