001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.marshall.jena;
018
019import static org.apache.juneau.commons.utils.CollectionUtils.*;
020import static org.apache.juneau.commons.utils.Shorts.*;
021import static org.apache.juneau.commons.utils.SystemUtils.*;
022
023import java.util.*;
024import java.util.concurrent.*;
025
026import org.apache.juneau.commons.bean.*;
027import org.apache.juneau.commons.collections.*;
028import org.apache.juneau.marshall.*;
029import org.apache.juneau.marshall.serializer.*;
030import org.apache.juneau.marshall.xml.*;
031
032/**
033 * Serializes POJOs to RDF.
034 *
035 * <h5 class='topic'>Behavior-specific subclasses</h5>
036 * <p>
037 * The following direct subclasses are provided for language-specific serializers:
038 * <ul>
039 *    <li>{@link RdfXmlSerializer} - RDF/XML.
040 *    <li>{@link RdfXmlAbbrevSerializer} - RDF/XML-ABBREV.
041 *    <li>{@link NTripleSerializer} - N-TRIPLE.
042 *    <li>{@link TurtleSerializer} - TURTLE.
043 *    <li>{@link N3Serializer} - N3.
044 * </ul>
045 *
046 * <h5 class='section'>Notes:</h5><ul>
047 *    <li class='note'>This class is thread safe and reusable.
048 * </ul>
049 *
050 * <h5 class='section'>See Also:</h5><ul>
051 *    <li class='link'>{doc jmr.RdfDetails}
052
053 * </ul>
054 */
055@SuppressWarnings({
056   "java:S100", // Builder methods use underscore-separated namespacing convention (e.g. n3_disableAbbrevBaseUri, rdfxml_xmlbase) to group related settings by Jena component
057   "java:S110", // Inheritance depth exceeds 5; necessary to participate in the serializer hierarchy
058   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
059})
060public class RdfSerializer extends WriterSerializer implements RdfMetaProvider {
061
062   // Media type and language constants
063   private static final String LANG_RDF_XML_ABBREV = "RDF/XML-ABBREV";
064   private static final String MT_TEXT_XML_RDF = "text/xml+rdf";
065
066   /**
067    * Builder class.
068    */
069   @SuppressWarnings({
070      "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name.
071   })
072   public abstract static class Builder<SELF extends Builder<SELF>> extends WriterSerializer.Builder<SELF> {
073
074      private static final Cache<HashKey,RdfSerializer> CACHE = Cache.of(HashKey.class, RdfSerializer.class).build();
075
076      private static final Namespace DEFAULT_JUNEAU_NS = Namespace.of("j", "http://www.apache.org/juneau/");
077      private static final Namespace DEFAULT_JUNEAUBP_NS = Namespace.of("jp", "http://www.apache.org/juneaubp/");
078
079      boolean addBeanTypesRdf;
080      boolean addLiteralTypes;
081      boolean addRootProperty;
082      boolean disableAutoDetectNamespaces;
083      boolean disableUseXmlNamespaces;
084      boolean looseCollections;
085      String language;
086      Namespace juneauNs;
087      Namespace juneauBpNs;
088      RdfCollectionFormat collectionFormat;
089      List<Namespace> namespaces;
090      Map<String,Object> jenaSettings;
091
092      /**
093       * Constructor, default settings.
094       */
095      protected Builder() {
096         super();
097         addBeanTypesRdf = env("Rdf.addBeanTypesRdf", false);
098         addLiteralTypes = env("Rdf.addLiteralTypes", false);
099         addRootProperty = env("Rdf.addRootProperty", false);
100         disableAutoDetectNamespaces = env("Rdf.disableAutoDetectNamespaces", false);
101         disableUseXmlNamespaces = env("Rdf.disableUseXmlNamespaces", false);
102         looseCollections = env("Rdf.looseCollections", false);
103         language = env("Rdf.language", LANG_RDF_XML_ABBREV);
104         collectionFormat = env("Rdf.collectionFormat", RdfCollectionFormat.DEFAULT);
105         juneauNs = DEFAULT_JUNEAU_NS;
106         juneauBpNs = DEFAULT_JUNEAUBP_NS;
107         namespaces = null;
108         jenaSettings = new TreeMap<>();
109      }
110
111      /**
112       * Copy constructor.
113       *
114       * @param copyFrom The builder to copy from.
115       *    <br>Cannot be <jk>null</jk>.
116       */
117      protected Builder(Builder<?> copyFrom) {
118         super(reqnn("copyFrom", copyFrom));
119         addBeanTypesRdf = copyFrom.addBeanTypesRdf;
120         addLiteralTypes = copyFrom.addLiteralTypes;
121         addRootProperty = copyFrom.addRootProperty;
122         collectionFormat = copyFrom.collectionFormat;
123         disableAutoDetectNamespaces = copyFrom.disableAutoDetectNamespaces;
124         disableUseXmlNamespaces = copyFrom.disableUseXmlNamespaces;
125         juneauBpNs = copyFrom.juneauBpNs;
126         juneauNs = copyFrom.juneauNs;
127         language = copyFrom.language;
128         looseCollections = copyFrom.looseCollections;
129         namespaces = copyFrom.namespaces;
130         jenaSettings = new TreeMap<>(copyFrom.jenaSettings);
131      }
132
133      /**
134       * Copy constructor.
135       *
136       * @param copyFrom The bean to copy from.
137       *    <br>Cannot be <jk>null</jk>.
138       */
139      protected Builder(RdfSerializer copyFrom) {
140         super(reqnn("copyFrom", copyFrom));
141         addBeanTypesRdf = copyFrom.addBeanTypesRdf;
142         addLiteralTypes = copyFrom.addLiteralTypes;
143         addRootProperty = copyFrom.addRootProperty;
144         collectionFormat = copyFrom.collectionFormat;
145         disableAutoDetectNamespaces = ! copyFrom.autoDetectNamespaces;
146         disableUseXmlNamespaces = ! copyFrom.useXmlNamespaces;
147         juneauBpNs = copyFrom.juneauBpNs;
148         juneauNs = copyFrom.juneauNs;
149         language = copyFrom.language;
150         looseCollections = copyFrom.looseCollections;
151         namespaces = copyFrom.namespaces.length == 0 ? null : list(copyFrom.namespaces);
152         jenaSettings = new TreeMap<>(copyFrom.jenaSettings);
153      }
154
155      /**
156       * Add <js>"_type"</js> properties when needed.
157       *
158       * <p>
159       * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred
160       * through reflection.
161       *
162       * <p>
163       * When present, this value overrides the {@link org.apache.juneau.marshall.serializer.Serializer.Builder#addBeanTypes() Serializer.Builder#addBeanTypes()} setting and is
164       * provided to customize the behavior of specific serializers in a {@link SerializerSet}.
165       *
166       * @return This object.
167       */
168      public SELF addBeanTypesRdf() {
169         return addBeanTypesRdf(true);
170      }
171
172      /**
173       * Same as {@link #addBeanTypesRdf()} but allows you to explicitly specify the value.
174       *
175       * @param value The value for this setting.
176       * @return This object.
177       */
178      public SELF addBeanTypesRdf(boolean value) {
179         addBeanTypesRdf = value;
180         return self();
181      }
182
183      /**
184       * Add XSI data types to non-<c>String</c> literals.
185       *
186       * <p>
187       * Shortcut for calling <code>addLiteralTypes(<jk>true</jk>)</code>.
188       *
189       * @return This object.
190       */
191      public SELF addLiteralTypes() {
192         return addLiteralTypes(true);
193      }
194
195      /**
196       * Add XSI data types to non-<c>String</c> literals.
197       *
198       * <p>
199       * Shortcut for calling <code>addLiteralTypes(<jk>true</jk>)</code>.
200       *
201       * @param value
202       *    The new value for this setting.
203       * @return This object.
204       */
205      public SELF addLiteralTypes(boolean value) {
206         addLiteralTypes = value;
207         return self();
208      }
209
210      /**
211       * Add RDF root identifier property to root node.
212       *
213       * <p>
214       * When enabled an RDF property <c>http://www.apache.org/juneau/root</c> is added with a value of <js>"true"</js>
215       * to identify the root node in the graph.
216       * <br>This helps locate the root node during parsing.
217       *
218       * <p>
219       * If disabled, the parser has to search through the model to find any resources without incoming predicates to
220       * identify root notes, which can introduce a considerable performance degradation.
221       *
222       * @return This object.
223       */
224      public SELF addRootProperty() {
225         return addRootProperty(true);
226      }
227
228      /**
229       * Add RDF root identifier property to root node.
230       *
231       * <p>
232       * When enabled an RDF property <c>http://www.apache.org/juneau/root</c> is added with a value of <js>"true"</js>
233       * to identify the root node in the graph.
234       * <br>This helps locate the root node during parsing.
235       *
236       * <p>
237       * If disabled, the parser has to search through the model to find any resources without incoming predicates to
238       * identify root notes, which can introduce a considerable performance degradation.
239       *
240       * @param value
241       *    The new value for this setting.
242       * @return This object.
243       */
244      public SELF addRootProperty(boolean value) {
245         addRootProperty = value;
246         return self();
247      }
248
249      @Override /* Overridden from Context.Builder<?> */
250      public RdfSerializer build() {
251         return cache(CACHE).build(RdfSerializer.class);
252      }
253
254      /**
255       * RDF format for representing collections and arrays.
256       *
257       * <ul class='values'>
258       *    <li><js>"DEFAULT"</js> - Default format.  The default is an RDF Sequence container.
259       *    <li><js>"SEQ"</js> - RDF Sequence container.
260       *    <li><js>"BAG"</js> - RDF Bag container.
261       *    <li><js>"LIST"</js> - RDF List container.
262       *    <li><js>"MULTI_VALUED"</js> - Multi-valued properties.
263       * </ul>
264       *
265       * <h5 class='section'>Notes:</h5><ul>
266       *    <li class='note'>
267       *       If you use <js>"BAG"</js> or <js>"MULTI_VALUED"</js>, the order of the elements in the collection will get
268       *       lost.
269       * </ul>
270       *
271       * @param value
272       *    The new value for this setting.
273       *    <br>Cannot be <jk>null</jk>.
274       * @return This object.
275       */
276      public SELF collectionFormat(RdfCollectionFormat value) {
277         collectionFormat = reqnn("value", value);
278         return self();
279      }
280
281      @Override /* Overridden from Context.Builder<?> */
282      public abstract SELF copy();
283
284      /**
285       * Disable auto-detect namespace usage.
286       *
287       * <p>
288       * Don't detect namespace usage before serialization.
289       *
290       * <p>
291       * If enabled, then the data structure will first be crawled looking for namespaces that will be encountered before
292       * the root element is serialized.
293       *
294       * @return This object.
295       */
296      public SELF disableAutoDetectNamespaces() {
297         return disableAutoDetectNamespaces(true);
298      }
299
300      /**
301       * Disable auto-detect namespace usage.
302       *
303       * <p>
304       * Don't detect namespace usage before serialization.
305       *
306       * <p>
307       * If enabled, then the data structure will first be crawled looking for namespaces that will be encountered before
308       * the root element is serialized.
309       *
310       * @param value
311       *    The new value for this setting.
312       * @return This object.
313       */
314      public SELF disableAutoDetectNamespaces(boolean value) {
315         disableAutoDetectNamespaces = value;
316         return self();
317      }
318
319      /**
320       * Disable reuse of XML namespaces when RDF namespaces not specified.
321       *
322       * <p>
323       * When enabled, namespaces defined using {@link XmlNs @XmlNs} and {@link Xml Xml} will not be
324       * inherited by the RDF serializers.
325       * Otherwise, namespaces will be defined using {@link RdfNs @RdfNs} and {@link Rdf @Rdf}.
326       *
327       * @return This object.
328       */
329      public SELF disableUseXmlNamespaces() {
330         return disableUseXmlNamespaces(true);
331      }
332
333      /**
334       * Disable reuse of XML namespaces when RDF namespaces not specified.
335       *
336       * <p>
337       * When enabled, namespaces defined using {@link XmlNs @XmlNs} and {@link Xml Xml} will not be
338       * inherited by the RDF serializers.
339       * Otherwise, namespaces will be defined using {@link RdfNs @RdfNs} and {@link Rdf @Rdf}.
340       *
341       * @param value
342       *    The new value for this setting.
343       * @return This object.
344       */
345      public SELF disableUseXmlNamespaces(boolean value) {
346         disableUseXmlNamespaces = value;
347         return self();
348      }
349
350      @Override /* Overridden from Context.Builder<?> */
351      public HashKey hashKey() {
352         // @formatter:off
353         return HashKey.of(
354            super.hashKey(),
355            addBeanTypesRdf,
356            addLiteralTypes,
357            addRootProperty,
358            disableAutoDetectNamespaces,
359            disableUseXmlNamespaces,
360            looseCollections,
361            language,
362            collectionFormat,
363            juneauNs,
364            juneauBpNs,
365            namespaces,
366            jenaSettings
367         );
368         // @formatter:on
369      }
370
371      /**
372       * Default XML namespace for bean properties.
373       *
374       * @param value
375       *    The new value for this setting.
376       *    <br>The default is <code>{j:<js>'http://www.apache.org/juneaubp/'</js>}</code>.
377       *    <br>Cannot be <jk>null</jk>.
378       * @return This object.
379       */
380      public SELF juneauBpNs(Namespace value) {
381         juneauBpNs = reqnn("value", value);
382         return self();
383      }
384
385      /**
386       * XML namespace for Juneau properties.
387       *
388       * @param value
389       *    The new value for this setting.
390       *    <br>The default is <code>{j:<js>'http://www.apache.org/juneau/'</js>}</code>.
391       *    <br>Cannot be <jk>null</jk>.
392       * @return This object.
393       */
394      public SELF juneauNs(Namespace value) {
395         juneauNs = reqnn("value", value);
396         return self();
397      }
398
399      /**
400       * RDF language.
401       *
402       * <p>
403       * Can be any of the following:
404       * <ul class='spaced-list'>
405       *    <li>
406       *       <js>"RDF/XML"</js>
407       *    <li>
408       *       <js>"RDF/XML-ABBREV"</js> (default)
409       *    <li>
410       *       <js>"N-TRIPLE"</js>
411       *    <li>
412       *       <js>"N3"</js> - General name for the N3 writer.
413       *       Will make a decision on exactly which writer to use (pretty writer, plain writer or simple writer) when
414       *       created.
415       *       Default is the pretty writer but can be overridden with system property
416       *       <c>org.apache.jena.n3.N3JenaWriter.writer</c>.
417       *    <li>
418       *       <js>"N3-PP"</js> - Name of the N3 pretty writer.
419       *       The pretty writer uses a frame-like layout, with prefixing, clustering like properties and embedding
420       *       one-referenced bNodes.
421       *    <li>
422       *       <js>"N3-PLAIN"</js> - Name of the N3 plain writer.
423       *       The plain writer writes records by subject.
424       *    <li>
425       *       <js>"N3-TRIPLES"</js> - Name of the N3 triples writer.
426       *       This writer writes one line per statement, like N-Triples, but does N3-style prefixing.
427       *    <li>
428       *       <js>"TURTLE"</js> -  Turtle writer.
429       *       http://www.dajobe.org/2004/01/turtle/
430       * </ul>
431       *
432       * <h5 class='section'>See Also:</h5><ul>
433       *    <li class='jm'>{@link #n3()}
434       *    <li class='jm'>{@link #ntriple()}
435       *    <li class='jm'>{@link #turtle()}
436       *    <li class='jm'>{@link #xml()}
437       *    <li class='jm'>{@link #xmlabbrev()}
438       * </ul>
439       *
440       * @param value
441       *    The new value for this setting.
442       *    <br>Cannot be <jk>null</jk>.
443       * @return This object.
444       */
445      public SELF language(String value) {
446         language = reqnn("value", value);
447         return self();
448      }
449
450      /**
451       * Collections should be serialized and parsed as loose collections.
452       *
453       * <p>
454       * When specified, collections of resources are handled as loose collections of resources in RDF instead of
455       * resources that are children of an RDF collection (e.g. Sequence, Bag).
456       *
457       * <p>
458       * Note that this setting is specialized for RDF syntax, and is incompatible with the concept of
459       * losslessly representing POJO models, since the tree structure of these POJO models are lost
460       * when serialized as loose collections.
461       *
462       * <p>
463       * This setting is typically only useful if the beans being parsed into do not have a bean property
464       * annotated with {@link Rdf#beanUri @Rdf(beanUri=true)}.
465       *
466       * <h5 class='section'>Example:</h5>
467       * <p class='bjava'>
468       *    WriterSerializer <jv>serializer</jv> = RdfSerializer
469       *       .<jsm>create</jsm>()
470       *       .xmlabbrev()
471       *       .looseCollections()
472       *       .build();
473       *
474       *    ReaderParser <jv>parser</jv> = RdfParser
475       *       .<jsm>create</jsm>()
476       *       .xml()
477       *       .looseCollections()
478       *       .build();
479       *
480       *    List&lt;MyBean&gt; <jv>list</jv> = <jsm>createListOfMyBeans</jsm>();
481       *
482       *    <jc>// Serialize to RDF/XML as loose resources</jc>
483       *    String <jv>rdfXml</jv> = <jv>serializer</jv>.write(<jv>list</jv>);
484       *
485       *    <jc>// Parse back into a Java collection</jc>
486       *    <jv>list</jv> = <jv>parser</jv>.read(<jv>rdfXml</jv>, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
487       *
488       *    MyBean[] <jv>beans</jv> = <jsm>createArrayOfMyBeans</jsm>();
489       *
490       *    <jc>// Serialize to RDF/XML as loose resources</jc>
491       *    <jv>rdfXml</jv> = <jv>serializer</jv>.write(<jv>beans</jv>);
492       *
493       *    <jc>// Parse back into a bean array</jc>
494       *    <jv>beans</jv> = <jv>parser</jv>.read(<jv>rdfXml</jv>, MyBean[].<jk>class</jk>);
495       * </p>
496       *
497       * @return This object.
498       */
499      public SELF looseCollections() {
500         return looseCollections(true);
501      }
502
503      /**
504       * Collections should be serialized and parsed as loose collections.
505       *
506       * <p>
507       * When specified, collections of resources are handled as loose collections of resources in RDF instead of
508       * resources that are children of an RDF collection (e.g. Sequence, Bag).
509       *
510       * <p>
511       * Note that this setting is specialized for RDF syntax, and is incompatible with the concept of
512       * losslessly representing POJO models, since the tree structure of these POJO models are lost
513       * when serialized as loose collections.
514       *
515       * <p>
516       * This setting is typically only useful if the beans being parsed into do not have a bean property
517       * annotated with {@link Rdf#beanUri @Rdf(beanUri=true)}.
518       *
519       * <h5 class='section'>Example:</h5>
520       * <p class='bjava'>
521       *    WriterSerializer <jv>serializer</jv> = RdfSerializer
522       *       .<jsm>create</jsm>()
523       *       .xmlabbrev()
524       *       .looseCollections()
525       *       .build();
526       *
527       *    ReaderParser <jv>parser</jv> = RdfParser
528       *       .<jsm>create</jsm>()
529       *       .xml()
530       *       .looseCollections()
531       *       .build();
532       *
533       *    List&lt;MyBean&gt; <jv>list</jv> = <jsm>createListOfMyBeans</jsm>();
534       *
535       *    <jc>// Serialize to RDF/XML as loose resources</jc>
536       *    String <jv>rdfXml</jv> = <jv>serializer</jv>.write(<jv>list</jv>);
537       *
538       *    <jc>// Parse back into a Java collection</jc>
539       *    <jv>list</jv> = <jv>parser</jv>.read(<jv>rdfXml</jv>, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
540       *
541       *    MyBean[] <jv>beans</jv> = <jsm>createArrayOfMyBeans</jsm>();
542       *
543       *    <jc>// Serialize to RDF/XML as loose resources</jc>
544       *    <jv>rdfXml</jv> = <jv>serializer</jv>.write(<jv>beans</jv>);
545       *
546       *    <jc>// Parse back into a bean array</jc>
547       *    <jv>beans</jv> = <jv>parser</jv>.read(<jv>rdfXml</jv>, MyBean[].<jk>class</jk>);
548       * </p>
549       *
550       * @param value
551       *    The new value for this setting.
552       * @return This object.
553       */
554      public SELF looseCollections(boolean value) {
555         looseCollections = value;
556         return self();
557      }
558
559      /**
560       * RDF language.
561       *
562       * <p>
563       * Shortcut for calling <code>language(<jsf>LANG_N3</jsf>)</code>
564       *
565       * @return This object.
566       */
567      public SELF n3() {
568         return language(Constants.LANG_N3);
569      }
570
571      /**
572       * N3/Turtle property: <c>disableAbbrevBaseURI</c>.
573       *
574       * <p>
575       * Controls whether to use abbreviations <c>&lt;&gt;</c> or <c>&lt;#&gt;</c>.
576       *
577       * @return This object.
578       */
579      public SELF n3_disableAbbrevBaseUri() {
580         return n3_disableAbbrevBaseUri(true);
581      }
582
583      /**
584       * N3/Turtle property: <c>disableAbbrevBaseURI</c>.
585       *
586       * <p>
587       * Controls whether to use abbreviations <c>&lt;&gt;</c> or <c>&lt;#&gt;</c>.
588       *
589       * @param value
590       *    The new value for this setting.
591       * @return This object.
592       */
593      public SELF n3_disableAbbrevBaseUri(boolean value) {
594         return jena("n3.disableAbbrevBaseUri", value);
595      }
596
597      /**
598       * N3/Turtle property: <c>disableObjectLists</c>.
599       *
600       * <p>
601       * Don't print object lists as comma separated lists.
602       *
603       * @return This object.
604       */
605      public SELF n3_disableObjectLists() {
606         return n3_disableObjectLists(true);
607      }
608
609      /**
610       * N3/Turtle property: <c>disableObjectLists</c>.
611       *
612       * <p>
613       * Don't print object lists as comma separated lists.
614       *
615       * @param value
616       *    The new value for this setting.
617       * @return This object.
618       */
619      public SELF n3_disableObjectLists(boolean value) {
620         return jena("n3.disableObjectLists", value);
621      }
622
623      /**
624       * N3/Turtle property: <c>disableUseDoubles</c>.
625       *
626       * <p>
627       * Disallow the use of doubles as <c>123.456</c>.
628       *
629       * @return This object.
630       */
631      public SELF n3_disableUseDoubles() {
632         return n3_disableUseDoubles(true);
633      }
634
635      /**
636       * N3/Turtle property: <c>disableUseDoubles</c>.
637       *
638       * <p>
639       * Disallow the use of doubles as <c>123.456</c>.
640       *
641       * @param value
642       *    The new value for this setting.
643       * @return This object.
644       */
645      public SELF n3_disableUseDoubles(boolean value) {
646         return jena("n3.disableUseDoubles", value);
647      }
648
649      /**
650       * N3/Turtle property: <c>disableUsePropertySymbols</c>.
651       *
652       * <p>
653       * Controls whether to use <c>a</c>, <c>=</c> and <c>=&gt;</c> in output
654       *
655       * @return This object.
656       */
657      public SELF n3_disableUsePropertySymbols() {
658         return n3_disableUsePropertySymbols(true);
659      }
660
661      /**
662       * N3/Turtle property: <c>disableUsePropertySymbols</c>.
663       *
664       * <p>
665       * Controls whether to use <c>a</c>, <c>=</c> and <c>=&gt;</c> in output
666       *
667       * @param value
668       *    The new value for this setting.
669       * @return This object.
670       */
671      public SELF n3_disableUsePropertySymbols(boolean value) {
672         return jena("n3.disableUsePropertySymbols", value);
673      }
674
675      /**
676       * N3/Turtle property: <c>disableUseTripleQuotedStrings</c>.
677       *
678       * <p>
679       * Disallow the use of <c>"""</c> to delimit long strings.
680       *
681       * @return This object.
682       */
683      public SELF n3_disableUseTripleQuotedStrings() {
684         return n3_disableUseTripleQuotedStrings(true);
685      }
686
687      /**
688       * N3/Turtle property: <c>disableUseTripleQuotedStrings</c>.
689       *
690       * <p>
691       * Disallow the use of <c>"""</c> to delimit long strings.
692       *
693       * @param value
694       *    The new value for this setting.
695       * @return This object.
696       */
697      public SELF n3_disableUseTripleQuotedStrings(boolean value) {
698         return jena("n3.disableUseTripleQuotedStrings", value);
699      }
700
701      /**
702       * N3/Turtle property: <c>indentProperty</c>.
703       *
704       * <p>
705       * Width to indent properties.
706       *
707       * @param value
708       *    The new value for this setting.
709       * @return This object.
710       */
711      public SELF n3_indentProperty(int value) {
712         return jena("n3.indentProperty", value);
713      }
714
715      /**
716       * N3/Turtle property: <c>minGap</c>.
717       *
718       * <p>
719       * Minimum gap between items on a line.
720       *
721       * @param value
722       *    The new value for this setting.
723       * @return This object.
724       */
725      public SELF n3_minGap(int value) {
726         return jena("n3.minGap", value);
727      }
728
729      /**
730       * N3/Turtle property: <c>propertyColumn</c>.
731       *
732       * <p>
733       * Width of the property column.
734       *
735       * @param value
736       *    The new value for this setting.
737       * @return This object.
738       */
739      public SELF n3_propertyColumn(int value) {
740         return jena("n3.propertyColumn", value);
741      }
742
743      /**
744       * N3/Turtle property: <c>subjectColumn</c>.
745       *
746       * <p>
747       * If the subject is shorter than this value, the first property may go on the same line.
748       *
749       * @param value
750       *    The new value for this setting.
751       * @return This object.
752       */
753      public SELF n3_subjectColumn(int value) {
754         return jena("n3.subjectColumn", value);
755      }
756
757      /**
758       * N3/Turtle property: <c>widePropertyLen</c>.
759       *
760       * <p>
761       * Width of the property column.
762       * Must be longer than <c>propertyColumn</c>.
763       *
764       * @param value
765       *    The new value for this setting.
766       * @return This object.
767       */
768      public SELF n3_widePropertyLen(int value) {
769         return jena("n3.widePropertyLen", value);
770      }
771
772      /**
773       * Default namespaces.
774       *
775       * <p>
776       * The default list of namespaces associated with this serializer.
777       *
778       * @param values The new value for this setting.
779       *    <br>Cannot contain <jk>null</jk> values (will throw {@link IllegalArgumentException}).
780       * @return This object.
781       */
782      public SELF namespaces(Namespace...values) {
783         reqnns("values", values);
784         namespaces = addAll(namespaces, values);
785         return self();
786      }
787
788      /**
789       * RDF language.
790       *
791       * <p>
792       * Shortcut for calling <code>language(<jsf>LANG_NTRIPLE</jsf>)</code>
793       *
794       * @return This object.
795       */
796      public SELF ntriple() {
797         return language(Constants.LANG_NTRIPLE);
798      }
799
800      /**
801       * RDF/XML property: <c>allowBadURIs</c>.
802       *
803       * <p>
804       * URIs in the graph are, by default, checked prior to serialization.
805       *
806       * @return This object.
807       */
808      public SELF rdfxml_allowBadUris() {
809         return rdfxml_allowBadUris(true);
810      }
811
812      /**
813       * RDF/XML property: <c>allowBadURIs</c>.
814       *
815       * <p>
816       * URIs in the graph are, by default, checked prior to serialization.
817       *
818       * @param value
819       *    The new value for this setting.
820       * @return This object.
821       */
822      public SELF rdfxml_allowBadUris(boolean value) {
823         return jena("rdfXml.allowBadURIs", value);
824      }
825
826      /**
827       * RDF/XML property: <c>attributeQuoteChar</c>.
828       *
829       * <p>
830       * The XML attribute quote character.
831       *
832       * @param value
833       *    The new value for this setting.
834       * @return This object.
835       */
836      public SELF rdfxml_attributeQuoteChar(char value) {
837         return jena("rdfXml.attributeQuoteChar", value);
838      }
839
840      /**
841       * RDF/XML property: <c>blockRules</c>.
842       *
843       * <p>
844       * A list of <c>Resource</c> or a <c>String</c> being a comma separated list of fragment IDs from
845       * {doc http://www.w3.org/TR/rdf-syntax-grammar RDF Syntax Grammar} indicating grammar
846       * rules that will not be used.
847       *
848       * @param value
849       *    The new value for this setting.
850       * @return This object.
851       */
852      public SELF rdfxml_blockRules(String value) {
853         return jena("rdfXml.blockRules", value);
854      }
855
856      /**
857       * RDF/XML property: <c>disableShowDoctypeDeclaration</c>.
858       *
859       * <p>
860       * If disabled, an XML doctype declaration isn't included in the output.
861       * This declaration includes a <c>!ENTITY</c> declaration for each prefix mapping in the model, and any
862       * attribute value that starts with the URI of that mapping is written as starting with the corresponding entity
863       * invocation.
864       *
865       * @return This object.
866       */
867      public SELF rdfxml_disableShowDoctypeDeclaration() {
868         return rdfxml_disableShowDoctypeDeclaration(true);
869      }
870
871      /**
872       * RDF/XML property: <c>disableShowDoctypeDeclaration</c>.
873       *
874       * <p>
875       * If disabled, an XML doctype declaration isn't included in the output.
876       * This declaration includes a <c>!ENTITY</c> declaration for each prefix mapping in the model, and any
877       * attribute value that starts with the URI of that mapping is written as starting with the corresponding entity
878       * invocation.
879       *
880       * @param value
881       *    The new value for this setting.
882       * @return This object.
883       */
884      public SELF rdfxml_disableShowDoctypeDeclaration(boolean value) {
885         return jena("rdfXml.disableShowDoctypeDeclaration", value);
886      }
887
888      /**
889       * RDF/XML ARP property: <c>error-mode</c>.
890       *
891       * <p>
892       * Sets ARP to look for RDF embedded within an enclosing XML document.
893       *
894       * <h5 class='section'>See Also:</h5><ul>
895       *    <li>
896       *       {doc ext.ARP/ARPOptions.html#setEmbedding(boolean) ARPOptions.setEmbedding(boolean)}
897       * </ul>
898       *
899       * @return This object.
900       */
901      public SELF rdfxml_embedding() {
902         return rdfxml_embedding(true);
903      }
904
905      /**
906       * RDF/XML ARP property: <c>error-mode</c>.
907       *
908       * <p>
909       * Sets ARP to look for RDF embedded within an enclosing XML document.
910       *
911       * <h5 class='section'>See Also:</h5><ul>
912       *    <li>
913       *       {doc ext.ARP/ARPOptions.html#setEmbedding(boolean) ARPOptions.setEmbedding(boolean)}
914       * </ul>
915       *
916       * @param value
917       *    The new value for this setting.
918       * @return This object.
919       */
920      public SELF rdfxml_embedding(boolean value) {
921         return jena("rdfXml.embedding", value);
922      }
923
924      /**
925       * RDF/XML ARP property: <c>error-mode</c>.
926       *
927       * <p>
928       * This allows a coarse-grained approach to control of error handling.
929       *
930       * <ul class='values'>
931       *    <li><js>"default"</js>
932       *    <li><js>"lax"</js>
933       *    <li><js>"strict"</js>
934       *    <li><js>"strict-ignore"</js>
935       *    <li><js>"strict-warning"</js>
936       *    <li><js>"strict-error"</js>
937       *    <li><js>"strict-fatal"</js>
938       * </ul>
939       *
940       * <h5 class='section'>See Also:</h5><ul>
941       *    <li>
942       *       {doc ext.ARP/ARPOptions.html#setDefaultErrorMode() ARPOptions.setDefaultErrorMode()}
943       *    <li>
944       *       {doc ext.ARP/ARPOptions.html#setLaxErrorMode() ARPOptions.setLaxErrorMode()}
945       *    <li>
946       *       {doc ext.ARP/ARPOptions.html#setStrictErrorMode() ARPOptions.setStrictErrorMode()}
947       *    <li>
948       *       {doc ext.ARP/ARPOptions.html#setStrictErrorMode(int) ARPOptions.setStrictErrorMode(int)}
949       * </ul>
950       *
951       * @param value
952       *    The new value for this setting.
953       * @return This object.
954       */
955      public SELF rdfxml_errorMode(String value) {
956         return jena("rdfXml.error-mode", value);
957      }
958
959      /**
960       * RDF/XML property: <c>iri_rules</c>.
961       *
962       * <p>
963       * Set the engine for checking and resolving.
964       *
965       * <ul class='values spaced-list'>
966       *    <li>
967       *       <js>"lax"</js> - The rules for RDF URI references only, which does permit spaces although the use of spaces
968       *       is not good practice.
969       *    <li>
970       *       <js>"strict"</js> - Sets the IRI engine with rules for valid IRIs, XLink and RDF; it does not permit spaces
971       *       in IRIs.
972       *    <li>
973       *       <js>"iri"</js> - Sets the IRI engine to IRI
974       *       ({doc http://www.ietf.org/rfc/rfc3986.txt RFC 3986},
975       *       {doc http://www.ietf.org/rfc/rfc3987.txt RFC 3987}).
976       * </ul>
977       *
978       * @param value
979       *    The new value for this setting.
980       * @return This object.
981       */
982      public SELF rdfxml_iriRules(String value) {
983         return jena("rdfXml.iri-rules", value);
984      }
985
986      /**
987       * RDF/XML property: <c>longId</c>.
988       *
989       * <p>
990       * Whether to use long ID's for anon resources.
991       * Short ID's are easier to read, but can run out of memory on very large models.
992       *
993       * @return This object.
994       */
995      public SELF rdfxml_longId() {
996         return rdfxml_longId(true);
997      }
998
999      /**
1000       * RDF/XML property: <c>longId</c>.
1001       *
1002       * <p>
1003       * Whether to use long ID's for anon resources.
1004       * Short ID's are easier to read, but can run out of memory on very large models.
1005       *
1006       * @param value
1007       *    The new value for this setting.
1008       * @return This object.
1009       */
1010      public SELF rdfxml_longId(boolean value) {
1011         return jena("rdfXml.longId", value);
1012      }
1013
1014      /**
1015       * RDF/XML property: <c>relativeURIs</c>.
1016       *
1017       * <p>
1018       * What sort of relative URIs should be used.
1019       *
1020       * <p>
1021       * A comma separate list of options:
1022       * <ul class='spaced-list'>
1023       *    <li>
1024       *       <js>"same-document"</js> - Same-document references (e.g. <js>""</js> or <js>"#foo"</js>)
1025       *    <li>
1026       *       <js>"network"</js>  - Network paths (e.g. <js>"//example.org/foo"</js> omitting the URI scheme)
1027       *    <li>
1028       *       <js>"absolute"</js> - Absolute paths (e.g. <js>"/foo"</js> omitting the scheme and authority)
1029       *    <li>
1030       *       <js>"relative"</js> - Relative path not beginning in <js>"../"</js>
1031       *    <li>
1032       *       <js>"parent"</js> - Relative path beginning in <js>"../"</js>
1033       *    <li>
1034       *       <js>"grandparent"</js> - Relative path beginning in <js>"../../"</js>
1035       * </ul>
1036       *
1037       * <p>
1038       * The default value is <js>"same-document, absolute, relative, parent"</js>.
1039       * To switch off relative URIs use the value <js>""</js>.
1040       * Relative URIs of any of these types are output where possible if and only if the option has been specified.
1041       *
1042       * @param value
1043       *    The new value for this setting.
1044       * @return This object.
1045       */
1046      public SELF rdfxml_relativeUris(String value) {
1047         return jena("rdfXml.relativeURIs", value);
1048      }
1049
1050      /**
1051       * RDF/XML property: <c>showXmlDeclaration</c>.
1052       *
1053       * <ul class='values spaced-list'>
1054       *    <li>
1055       *       <js>"true"</js> - Add XML Declaration to the output.
1056       *    <li>
1057       *       <js>"false"</js> - Don't add XML Declaration to the output.
1058       *    <li>
1059       *       <js>"default"</js> - Only add an XML Declaration when asked to write to an <c>OutputStreamWriter</c>
1060       *       that uses some encoding other than <c>UTF-8</c> or <c>UTF-16</c>.
1061       *       In this case the encoding is shown in the XML declaration.
1062       * </ul>
1063       *
1064       * @param value
1065       *    The new value for this setting.
1066       * @return This object.
1067       */
1068      public SELF rdfxml_showXmlDeclaration(String value) {
1069         return jena("rdfXml.showXmlDeclaration", value);
1070      }
1071
1072      /**
1073       * RDF/XML property: <c>tab</c>.
1074       *
1075       * <p>
1076       * The number of spaces with which to indent XML child elements.
1077       *
1078       * @param value
1079       *    The new value for this setting.
1080       * @return This object.
1081       */
1082      public SELF rdfxml_tab(int value) {
1083         return jena("rdfXml.tab", value);
1084      }
1085
1086      /**
1087       * RDF/XML property: <c>xmlbase</c>.
1088       *
1089       * <p>
1090       * The value to be included for an <xa>xml:base</xa> attribute on the root element in the file.
1091       *
1092       * @param value
1093       *    The new value for this setting.
1094       * @return This object.
1095       */
1096      public SELF rdfxml_xmlbase(String value) {
1097         return jena("rdfXml.xmlbase", value);
1098      }
1099
1100      /**
1101       * RDF language.
1102       *
1103       * <p>
1104       * Shortcut for calling <code>language(<jsf>LANG_TURTLE</jsf>)</code>
1105       *
1106       * @return This object.
1107       */
1108      public SELF turtle() {
1109         return language(Constants.LANG_TURTLE);
1110      }
1111
1112      /**
1113       * RDF language.
1114       *
1115       * <p>
1116       * Shortcut for calling <code>language(<jsf>LANG_JSONLD</jsf>)</code>
1117       *
1118       * @return This object.
1119       */
1120      public SELF jsonLd() {
1121         return language(Constants.LANG_JSONLD);
1122      }
1123
1124      /**
1125       * RDF language.
1126       *
1127       * <p>
1128       * Shortcut for calling <code>language(<jsf>LANG_NQUADS</jsf>)</code>
1129       *
1130       * @return This object.
1131       */
1132      public SELF nQuads() {
1133         return language(Constants.LANG_NQUADS);
1134      }
1135
1136      /**
1137       * RDF language.
1138       *
1139       * <p>
1140       * Shortcut for calling <code>language(<jsf>LANG_TRIG</jsf>)</code>
1141       *
1142       * @return This object.
1143       */
1144      public SELF triG() {
1145         return language(Constants.LANG_TRIG);
1146      }
1147
1148      /**
1149       * RDF language.
1150       *
1151       * <p>
1152       * Shortcut for calling <code>language(<jsf>LANG_TRIX</jsf>)</code>
1153       *
1154       * @return This object.
1155       */
1156      public SELF triX() {
1157         return language(Constants.LANG_TRIX);
1158      }
1159
1160      /**
1161       * RDF language.
1162       *
1163       * <p>
1164       * Shortcut for calling <code>language(<jsf>LANG_RDFJSON</jsf>)</code>
1165       *
1166       * @return This object.
1167       */
1168      public SELF rdfJson() {
1169         return language(Constants.LANG_RDFJSON);
1170      }
1171
1172
1173      /**
1174       * RDF language.
1175       *
1176       * <p>
1177       * Shortcut for calling <code>language(<jsf>LANG_RDF_XML</jsf>)</code>
1178       *
1179       * @return This object.
1180       */
1181      public SELF xml() {
1182         return language(Constants.LANG_RDF_XML);
1183      }
1184
1185      /**
1186       * RDF language.
1187       *
1188       * <p>
1189       * Shortcut for calling <code>language(<jsf>LANG_RDF_XML_ABBREV</jsf>)</code>
1190       *
1191       * @return This object.
1192       */
1193      public SELF xmlabbrev() {
1194         return language(Constants.LANG_RDF_XML_ABBREV);
1195      }
1196
1197      SELF jena(String key, Object value) {
1198         jenaSettings.put(key, value);
1199         return self();
1200      }
1201   }
1202
1203   /**
1204    * Concrete default builder leaf for the non-subclassed {@link RdfSerializer#create()} / {@link RdfSerializer#copy()} path.
1205    */
1206   public static final class DefaultBuilder extends Builder<DefaultBuilder> {
1207
1208      DefaultBuilder() {}
1209
1210      DefaultBuilder(RdfSerializer copyFrom) {
1211         super(copyFrom);
1212      }
1213
1214      DefaultBuilder(Builder<?> copyFrom) {
1215         super(copyFrom);
1216      }
1217
1218      @Override /* Overridden from Context.Builder<?> */
1219      public DefaultBuilder copy() {
1220         return new DefaultBuilder(this);
1221      }
1222   }
1223
1224   private static final Namespace[] EMPTY_NAMESPACE_ARRAY = new Namespace[0];
1225
1226   /**
1227    * Creates a new builder for this object.
1228    *
1229    * @return A new builder.
1230    */
1231   @SuppressWarnings({
1232      "java:S1452", // Builder<?> wildcard return intentional; callers chain via fluent API without needing the concrete type
1233      "java:S9149" // Public Juneau DSL factory; hiding parent create() is intentional.
1234   })
1235   public static Builder<?> create() {
1236      return new DefaultBuilder();
1237   }
1238
1239   private static String getAccept(Builder<?> builder) {
1240      if (nn(builder.getAccept()))
1241         return builder.getAccept();
1242      return switch (builder.language) {
1243         case "RDF/XML" -> "text/xml+rdf+abbrev";
1244         case LANG_RDF_XML_ABBREV -> "text/xml+rdf+abbrev,text/xml+rdf;q=0.9";
1245         case "N-TRIPLE" -> "text/n-triple";
1246         case "N3" -> "text/n3";
1247         case "N3-PP" -> "text/n3-pp";
1248         case "N3-PLAIN" -> "text/n3-plain";
1249         case "N3-TRIPLES" -> "text/n3-triples";
1250         case "TURTLE" -> "text/turtle";
1251         case "JSON-LD" -> "application/ld+json";
1252         case "N-QUADS" -> "application/n-quads";
1253         case "TRIG" -> "application/trig";
1254         case "TRIX" -> "application/trix+xml";
1255         case "RDF/JSON" -> "application/rdf+json";
1256         default -> MT_TEXT_XML_RDF;
1257      };
1258   }
1259
1260   private static String getProduces(Builder<?> builder) {
1261      if (nn(builder.getProduces()))
1262         return builder.getProduces();
1263      return switch (builder.language) {
1264         case "RDF/XML" -> "text/xml+rdf+abbrev";
1265         case LANG_RDF_XML_ABBREV -> MT_TEXT_XML_RDF;
1266         case "N-TRIPLE" -> "text/n-triple";
1267         case "N3" -> "text/n3";
1268         case "N3-PP" -> "text/n3-pp";
1269         case "N3-PLAIN" -> "text/n3-plain";
1270         case "N3-TRIPLES" -> "text/n3-triples";
1271         case "TURTLE" -> "text/turtle";
1272         case "JSON-LD" -> "application/ld+json";
1273         case "N-QUADS" -> "application/n-quads";
1274         case "TRIG" -> "application/trig";
1275         case "TRIX" -> "application/trix+xml";
1276         case "RDF/JSON" -> "application/rdf+json";
1277         default -> MT_TEXT_XML_RDF;
1278      };
1279   }
1280
1281   protected final boolean addBeanTypesRdf;
1282   protected final boolean addLiteralTypes;
1283   protected final boolean addRootProperty;
1284   protected final boolean autoDetectNamespaces;
1285   protected final boolean looseCollections;
1286   protected final boolean useXmlNamespaces;
1287   protected final Namespace juneauBpNs;
1288   protected final Namespace juneauNs;
1289   protected final RdfCollectionFormat collectionFormat;
1290   protected final String language;
1291
1292   final Map<String,Object> jenaSettings;
1293   final Namespace[] namespaces;
1294   private final boolean addBeanTypesEffective;
1295   private final Map<ClassMeta<?>,RdfClassMeta> rdfClassMetas = new ConcurrentHashMap<>();
1296
1297   private final Map<BeanMeta<?>,RdfBeanMeta> rdfBeanMetas = new ConcurrentHashMap<>();
1298   private final Map<BeanPropertyMeta,RdfBeanPropertyMeta> rdfBeanPropertyMetas = new ConcurrentHashMap<>();
1299   private final Map<ClassMeta<?>,XmlClassMeta> xmlClassMetas = new ConcurrentHashMap<>();
1300
1301   private final Map<BeanMeta<?>,XmlBeanMeta> xmlBeanMetas = new ConcurrentHashMap<>();
1302
1303   private final Map<BeanPropertyMeta,XmlBeanPropertyMeta> xmlBeanPropertyMetas = new ConcurrentHashMap<>();
1304
1305   /**
1306    * Constructor.
1307    *
1308    * @param builder
1309    *    The builder for this object.
1310    *    <br>Cannot be <jk>null</jk>.
1311    */
1312   public RdfSerializer(Builder<?> builder) {
1313      super(builder.produces(getProduces(builder)).accept(getAccept(builder)));
1314      addLiteralTypes = builder.addLiteralTypes;
1315      addRootProperty = builder.addRootProperty;
1316      useXmlNamespaces = ! builder.disableUseXmlNamespaces;
1317      looseCollections = builder.looseCollections;
1318      autoDetectNamespaces = ! builder.disableAutoDetectNamespaces;
1319      language = builder.language;
1320      juneauNs = builder.juneauNs;
1321      juneauBpNs = builder.juneauBpNs;
1322      collectionFormat = builder.collectionFormat;
1323      namespaces = nn(builder.namespaces) ? builder.namespaces.toArray(EMPTY_NAMESPACE_ARRAY) : EMPTY_NAMESPACE_ARRAY;
1324      addBeanTypesRdf = builder.addBeanTypesRdf;
1325      jenaSettings = new TreeMap<>(builder.jenaSettings);
1326
1327      addBeanTypesEffective = addBeanTypesRdf || super.isAddBeanTypes();
1328   }
1329
1330   @Override /* Overridden from Context */
1331   public Builder<?> copy() {
1332      return new DefaultBuilder(this);
1333   }
1334
1335   @Override /* Overridden from Context */
1336   public RdfSerializerSession.Builder createSession() {
1337      return RdfSerializerSession.create(this);
1338   }
1339
1340   /**
1341    * Default namespaces.
1342    *
1343    * @see RdfSerializer.Builder#namespaces(Namespace...)
1344    * @return
1345    *    The default list of namespaces associated with this serializer.
1346    */
1347   public Namespace[] getNamespaces() { return cp(namespaces); }
1348
1349   @Override /* Overridden from RdfMetaProvider */
1350   public RdfBeanMeta getRdfBeanMeta(BeanMeta<?> bm) {
1351      return rdfBeanMetas.computeIfAbsent(bm, k -> new RdfBeanMeta(k, this));
1352   }
1353
1354   @Override /* Overridden from RdfMetaProvider */
1355   public RdfBeanPropertyMeta getRdfBeanPropertyMeta(BeanPropertyMeta bpm) {
1356      return rdfBeanPropertyMetas.computeIfAbsent(bpm, k -> new RdfBeanPropertyMeta(k.getDelegateFor(), this));
1357   }
1358
1359   @Override /* Overridden from RdfMetaProvider */
1360   public RdfClassMeta getRdfClassMeta(ClassMeta<?> cm) {
1361      return rdfClassMetas.computeIfAbsent(cm, k -> new RdfClassMeta(k, this));
1362   }
1363
1364   @Override /* Overridden from Context */
1365   public RdfSerializerSession getSession() { return createSession().build(); }
1366
1367   @Override /* Overridden from XmlMetaProvider */
1368   public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {
1369      return xmlBeanMetas.computeIfAbsent(bm, k -> new XmlBeanMeta(k, this));
1370   }
1371
1372   @Override /* Overridden from XmlMetaProvider */
1373   public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {
1374      return xmlBeanPropertyMetas.computeIfAbsent(bpm, k -> new XmlBeanPropertyMeta(k.getDelegateFor(), this));
1375   }
1376
1377   @Override /* Overridden from XmlMetaProvider */
1378   public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {
1379      return xmlClassMetas.computeIfAbsent(cm, k -> new XmlClassMeta(k, this));
1380   }
1381
1382   /**
1383    * RDF format for representing collections and arrays.
1384    *
1385    * @see RdfSerializer.Builder#collectionFormat(RdfCollectionFormat)
1386    * @return
1387    *    RDF format for representing collections and arrays.
1388    */
1389   protected final RdfCollectionFormat getCollectionFormat() { return collectionFormat; }
1390
1391   /**
1392    * All Jena-related configuration properties.
1393    *
1394    * @return
1395    *    A map of all Jena-related configuration properties.
1396    */
1397   protected final Map<String,Object> getJenaSettings() { return u(jenaSettings); }
1398
1399   /**
1400    * Default XML namespace for bean properties.
1401    *
1402    * @see RdfSerializer.Builder#juneauBpNs(Namespace)
1403    * @return
1404    *    The XML namespace to use for bean properties.
1405    */
1406   protected final Namespace getJuneauBpNs() { return juneauBpNs; }
1407
1408   /**
1409    * XML namespace for Juneau properties.
1410    *
1411    * @see RdfSerializer.Builder#juneauNs(Namespace)
1412    * @return
1413    *    The XML namespace to use for Juneau properties.
1414    */
1415   protected final Namespace getJuneauNs() { return juneauNs; }
1416
1417   /**
1418    * RDF language.
1419    *
1420    * @see RdfSerializer.Builder#language(String)
1421    * @return
1422    *    The RDF language to use.
1423    */
1424   protected final String getLanguage() { return language; }
1425
1426   /**
1427    * Add <js>"_type"</js> properties when needed.
1428    *
1429    * @see RdfSerializer.Builder#addBeanTypes()
1430    * @return
1431    *    <jk>true</jk> if <js>"_type"</js> properties will be added to beans if their type cannot be inferred
1432    *    through reflection.
1433    */
1434   @Override
1435   protected final boolean isAddBeanTypes() { return addBeanTypesEffective; }
1436
1437   /**
1438    * Add XSI data types to non-<c>String</c> literals.
1439    *
1440    * @see RdfSerializer.Builder#addLiteralTypes()
1441    * @return
1442    *    <jk>true</jk> if XSI data types should be added to string literals.
1443    */
1444   protected final boolean isAddLiteralTypes() { return addLiteralTypes; }
1445
1446   /**
1447    * Add RDF root identifier property to root node.
1448    *
1449    * @see RdfSerializer.Builder#addRootProperty()
1450    * @return
1451    *    <jk>true</jk> if RDF property <c>http://www.apache.org/juneau/root</c> is added with a value of <js>"true"</js>
1452    *    to identify the root node in the graph.
1453    */
1454   protected final boolean isAddRootProp() { return addRootProperty; }
1455
1456   /**
1457    * Auto-detect namespace usage.
1458    *
1459    * @see RdfSerializer.Builder#disableAutoDetectNamespaces()
1460    * @return
1461    *    <jk>true</jk> if namespaces usage should be detected before serialization.
1462    */
1463   protected final boolean isAutoDetectNamespaces() { return autoDetectNamespaces; }
1464
1465   /**
1466    * Collections should be serialized and parsed as loose collections.
1467    *
1468    * @see RdfSerializer.Builder#looseCollections()
1469    * @return
1470    *    <jk>true</jk> if collections of resources are handled as loose collections of resources in RDF instead of
1471    *    resources that are children of an RDF collection (e.g. Sequence, Bag).
1472    */
1473   protected final boolean isLooseCollections() { return looseCollections; }
1474
1475   /**
1476    * Reuse XML namespaces when RDF namespaces not specified.
1477    *
1478    * @see RdfSerializer.Builder#disableUseXmlNamespaces()
1479    * @return
1480    *    <jk>true</jk> if namespaces defined using {@link XmlNs @XmlNs} and {@link Xml @Xml} will be inherited by the RDF serializers.
1481    *    <br>Otherwise, namespaces will be defined using {@link RdfNs @RdfNs} and {@link Rdf @Rdf}.
1482    */
1483   protected final boolean isUseXmlNamespaces() { return useXmlNamespaces; }
1484
1485   @Override /* Overridden from WriterSerializer */
1486   protected FluentMap<String,Object> properties() {
1487      return super.properties()
1488         .a("addBeanTypes", addBeanTypes)
1489         .a("addLiteralTypes", addLiteralTypes)
1490         .a("addRootProperty", addRootProperty)
1491         .a("autoDetectNamespaces", autoDetectNamespaces)
1492         .a("collectionFormat", collectionFormat)
1493         .a("juneauBpNs", juneauBpNs)
1494         .a("juneauNs", juneauNs)
1495         .a("language", language)
1496         .a("looseCollections", looseCollections)
1497         .a("namespaces", namespaces)
1498         .a("useXmlNamespaces", useXmlNamespaces);
1499   }
1500}