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.jena.Constants.*;
016
017import java.util.*;
018
019import org.apache.juneau.*;
020import org.apache.juneau.parser.*;
021import org.apache.juneau.xml.*;
022
023/**
024 * Parses RDF into POJOs.
025 * 
026 * <h5 class='topic'>Behavior-specific subclasses</h5>
027 * 
028 * The following direct subclasses are provided for language-specific parsers:
029 * <ul class='spaced-list'>
030 *    <li>
031 *       {@link RdfParser.Xml} - RDF/XML and RDF/XML-ABBREV.
032 *    <li>
033 *       {@link RdfParser.NTriple} - N-TRIPLE.
034 *    <li>
035 *       {@link RdfParser.Turtle} - TURTLE.
036 *    <li>
037 *       {@link RdfParser.N3} - N3.
038 * </ul>
039 * 
040 * <h5 class='section'>See Also:</h5>
041 * <ul>
042 *    <li class='link'><a class="doclink" href="package-summary.html#TOC">org.apache.juneau.jena &gt; RDF Overview</a>
043 * </ul>
044 */
045public class RdfParser extends ReaderParser implements RdfCommon {
046
047   private static final Namespace 
048      DEFAULT_JUNEAU_NS = Namespace.create("j", "http://www.apache.org/juneau/"),
049      DEFAULT_JUNEAUBP_NS = Namespace.create("jp", "http://www.apache.org/juneaubp/");
050
051   //-------------------------------------------------------------------------------------------------------------------
052   // Configurable properties
053   //-------------------------------------------------------------------------------------------------------------------
054
055   private static final String PREFIX = "RdfParser.";
056
057   /**
058    * Configuration property:  Trim whitespace from text elements.
059    * 
060    * <h5 class='section'>Property:</h5>
061    * <ul>
062    *    <li><b>Name:</b>  <js>"RdfParser.trimWhitespace.b"</js>
063    *    <li><b>Data type:</b>  <code>Boolean</code>
064    *    <li><b>Default:</b>  <jk>false</jk>
065    *    <li><b>Session-overridable:</b>  <jk>true</jk>
066    *    <li><b>Methods:</b> 
067    *       <ul>
068    *          <li class='jm'>{@link RdfParserBuilder#trimWhitespace(boolean)}
069    *          <li class='jm'>{@link RdfParserBuilder#trimWhitespace()}
070    *       </ul>
071    * </ul>
072    * 
073    * <h5 class='section'>Description:</h5>
074    * <p>
075    * If <jk>true</jk>, whitespace in text elements will be automatically trimmed.
076    * 
077    * <h5 class='section'>Example:</h5>
078    * <p class='bcode'>
079    *    <jc>// Create an RDF parser that trims whitespace.</jc>
080    *    ReaderParser p = RdfParser
081    *       .<jsm>create</jsm>()
082    *       .xml()
083    *       .trimWhitespace()
084    *       .build();
085    *    
086    *    <jc>// Same, but use property.</jc>
087    *    ReaderParser p = RdfParser
088    *       .<jsm>create</jsm>()
089    *       .xml()
090    *       .set(<jsf>RDF_trimWhitespace</jsf>, <jk>true</jk>)
091    *       .build();
092    * </p>
093    */
094   public static final String RDF_trimWhitespace = PREFIX + "trimWhitespace.b";
095
096   
097   //-------------------------------------------------------------------------------------------------------------------
098   // Predefined instances
099   //-------------------------------------------------------------------------------------------------------------------
100   
101   /** Default XML parser, all default settings.*/
102   public static final RdfParser DEFAULT_XML = new Xml(PropertyStore.DEFAULT);
103
104   /** Default Turtle parser, all default settings.*/
105   public static final RdfParser DEFAULT_TURTLE = new Turtle(PropertyStore.DEFAULT);
106
107   /** Default N-Triple parser, all default settings.*/
108   public static final RdfParser DEFAULT_NTRIPLE = new NTriple(PropertyStore.DEFAULT);
109
110   /** Default N3 parser, all default settings.*/
111   public static final RdfParser DEFAULT_N3 = new N3(PropertyStore.DEFAULT);
112
113
114   //-------------------------------------------------------------------------------------------------------------------
115   // Predefined subclasses
116   //-------------------------------------------------------------------------------------------------------------------
117
118   /** Consumes RDF/XML input */
119   public static class Xml extends RdfParser {
120
121      /**
122       * Constructor.
123       * 
124       * @param ps The property store containing all the settings for this object.
125       */
126      public Xml(PropertyStore ps) {
127         super(
128            ps.builder()
129               .set(RDF_language, LANG_RDF_XML)
130               .build(), 
131            "text/xml+rdf"
132         );
133      }
134   }
135
136   /** Consumes N-Triple input */
137   public static class NTriple extends RdfParser {
138
139      /**
140       * Constructor.
141       * 
142       * @param ps The property store containing all the settings for this object.
143       */
144      public NTriple(PropertyStore ps) {
145         super(
146            ps.builder()
147               .set(RDF_language, LANG_NTRIPLE)
148               .build(), 
149            "text/n-triple"
150         );
151      }
152   }
153
154   /** Consumes Turtle input */
155   public static class Turtle extends RdfParser {
156
157      /**
158       * Constructor.
159       * 
160       * @param ps The property store containing all the settings for this object.
161       */
162      public Turtle(PropertyStore ps) {
163         super(
164            ps.builder()
165               .set(RDF_language, LANG_TURTLE)
166               .build(), 
167            "text/turtle"
168         );
169      }
170   }
171
172   /** Consumes N3 input */
173   public static class N3 extends RdfParser {
174
175      /**
176       * Constructor.
177       * 
178       * @param ps The property store containing all the settings for this object.
179       */
180      public N3(PropertyStore ps) {
181         super(
182            ps.builder()
183               .set(RDF_language, LANG_N3)
184               .build(), 
185            "text/n3"
186         );
187      }
188   }
189   
190   //-------------------------------------------------------------------------------------------------------------------
191   // Instance
192   //-------------------------------------------------------------------------------------------------------------------
193
194   final boolean trimWhitespace, looseCollections;
195   final String rdfLanguage;
196   final Namespace juneauNs, juneauBpNs;
197   final RdfCollectionFormat collectionFormat;
198   final Map<String,Object> jenaSettings = new HashMap<>();
199
200   /**
201    * Constructor.
202    * 
203    * @param ps The property store containing all the settings for this object.
204    * @param consumes The list of media types that this parser consumes (e.g. <js>"application/json"</js>).
205    */
206   public RdfParser(PropertyStore ps, String...consumes) {
207      super(ps, consumes);
208      trimWhitespace = getBooleanProperty(RDF_trimWhitespace, false);
209      looseCollections = getBooleanProperty(RDF_looseCollections, false);
210      rdfLanguage = getStringProperty(RDF_language, "RDF/XML-ABBREV");
211      juneauNs = getInstanceProperty(RDF_juneauNs, Namespace.class, DEFAULT_JUNEAU_NS);
212      juneauBpNs = getInstanceProperty(RDF_juneauBpNs, Namespace.class, DEFAULT_JUNEAUBP_NS);
213      collectionFormat = getProperty(RDF_collectionFormat, RdfCollectionFormat.class, RdfCollectionFormat.DEFAULT);
214   }
215   
216   /**
217    * Constructor.
218    * 
219    * @param ps The property store containing all the settings for this object.
220    */
221   public RdfParser(PropertyStore ps) {
222      this(ps, "text/xml+rdf");
223   }  
224   
225   @Override /* Context */
226   public RdfParserBuilder builder() {
227      return new RdfParserBuilder(getPropertyStore());
228   }
229
230   /**
231    * Instantiates a new clean-slate {@link RdfParserBuilder} object.
232    * 
233    * <p>
234    * This is equivalent to simply calling <code><jk>new</jk> RdfParserBuilder()</code>.
235    * 
236    * <p>
237    * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies 
238    * the settings of the object called on.
239    * 
240    * @return A new {@link RdfParserBuilder} object.
241    */
242   public static RdfParserBuilder create() {
243      return new RdfParserBuilder();
244   }
245
246   @Override /* Parser */
247   public ReaderParserSession createSession(ParserSessionArgs args) {
248      return new RdfParserSession(this, args);
249   }
250   
251   @Override /* Context */
252   public ObjectMap asMap() {
253      return super.asMap()
254         .append("RdfParser", new ObjectMap()
255            .append("trimWhitespace", trimWhitespace)
256            .append("looseCollections", looseCollections)
257            .append("rdfLanguage", rdfLanguage)
258            .append("juneauNs", juneauNs)
259            .append("juneauBpNs", juneauBpNs)
260            .append("collectionFormat", collectionFormat)
261         );
262   }
263}