1 /*
2  * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package com.sun.org.apache.xalan.internal.xsltc.runtime;
22 
23 import com.sun.org.apache.xalan.internal.XalanConstants;
24 import com.sun.org.apache.xalan.internal.xsltc.DOM;
25 import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
26 import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
27 import com.sun.org.apache.xalan.internal.xsltc.Translet;
28 import com.sun.org.apache.xalan.internal.xsltc.TransletException;
29 import com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter;
30 import com.sun.org.apache.xalan.internal.xsltc.dom.KeyIndex;
31 import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
32 import com.sun.org.apache.xml.internal.dtm.DTM;
33 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
34 import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
35 import java.io.BufferedOutputStream;
36 import java.io.File;
37 import java.io.FileOutputStream;
38 import java.text.DecimalFormat;
39 import java.text.DecimalFormatSymbols;
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44 import javax.xml.parsers.DocumentBuilderFactory;
45 import javax.xml.parsers.ParserConfigurationException;
46 import javax.xml.transform.Templates;
47 import jdk.xml.internal.JdkXmlUtils;
48 import org.w3c.dom.DOMImplementation;
49 import org.w3c.dom.Document;
50 
51 /**
52  * @author Jacek Ambroziak
53  * @author Santiago Pericas-Geertsen
54  * @author Morten Jorgensen
55  * @author G. Todd Miller
56  * @author John Howard, JohnH@schemasoft.com
57  * @LastModified: Oct 2017
58  */
59 public abstract class AbstractTranslet implements Translet {
60 
61     // These attributes are extracted from the xsl:output element. They also
62     // appear as fields (with the same type, only public) in Output.java
63     public String  _version = "1.0";
64     public String  _method = null;
65     public String  _encoding = "UTF-8";
66     public boolean _omitHeader = false;
67     public String  _standalone = null;
68     //see OutputPropertiesFactory.ORACLE_IS_STANDALONE
69     public boolean  _isStandalone = false;
70     public String  _doctypePublic = null;
71     public String  _doctypeSystem = null;
72     public boolean _indent = false;
73     public String  _mediaType = null;
74     public List<String> _cdata = null;
75     public int _indentamount = -1;
76 
77     public static final int FIRST_TRANSLET_VERSION = 100;
78     public static final int VER_SPLIT_NAMES_ARRAY = 101;
79     public static final int CURRENT_TRANSLET_VERSION = VER_SPLIT_NAMES_ARRAY;
80 
81     // Initialize Translet version field to base value.  A class that extends
82     // AbstractTranslet may override this value to a more recent translet
83     // version; if it doesn't override the value (because it was compiled
84     // before the notion of a translet version was introduced, it will get
85     // this default value).
86     protected int transletVersion = FIRST_TRANSLET_VERSION;
87 
88     // DOM/translet handshaking - the arrays are set by the compiled translet
89     protected String[] namesArray;
90     protected String[] urisArray;
91     protected int[]    typesArray;
92     protected String[] namespaceArray;
93 
94     // The Templates object that is used to create this Translet instance
95     protected Templates _templates = null;
96 
97     // Boolean flag to indicate whether this translet has id functions.
98     protected boolean _hasIdCall = false;
99 
100     // TODO - these should only be instanciated when needed
101     protected StringValueHandler stringValueHandler = new StringValueHandler();
102 
103     // Use one empty string instead of constantly instanciating String("");
104     private final static String EMPTYSTRING = "";
105 
106     // This is the name of the index used for ID attributes
107     private final static String ID_INDEX_NAME = "##id";
108 
109     private boolean _overrideDefaultParser;
110 
111     // The OutputStream for redirect function
112     private FileOutputStream output = null;
113 
114     /**
115      * protocols allowed for external references set by the stylesheet processing instruction, Document() function, Import and Include element.
116      */
117     private String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
118 
119     /************************************************************************
120      * Debugging
121      ************************************************************************/
printInternalState()122     public void printInternalState() {
123         System.out.println("-------------------------------------");
124         System.out.println("AbstractTranslet this = " + this);
125         System.out.println("pbase = " + pbase);
126         System.out.println("vframe = " + pframe);
127         System.out.println("paramsStack.size() = " + paramsStack.size());
128         System.out.println("namesArray.size = " + namesArray.length);
129         System.out.println("namespaceArray.size = " + namespaceArray.length);
130         System.out.println("");
131         System.out.println("Total memory = " + Runtime.getRuntime().totalMemory());
132     }
133 
134     /**
135      * Wrap the initial input DOM in a dom adapter. This adapter is wrapped in
136      * a DOM multiplexer if the document() function is used (handled by compiled
137      * code in the translet - see compiler/Stylesheet.compileTransform()).
138      */
makeDOMAdapter(DOM dom)139     public final DOMAdapter makeDOMAdapter(DOM dom)
140         throws TransletException {
141         setRootForKeys(dom.getDocument());
142         return new DOMAdapter(dom, namesArray, urisArray, typesArray, namespaceArray);
143     }
144 
145     /************************************************************************
146      * Parameter handling
147      ************************************************************************/
148 
149     // Parameter's stack: <tt>pbase</tt> and <tt>pframe</tt> are used
150     // to denote the current parameter frame.
151     protected int pbase = 0, pframe = 0;
152     protected List<Object> paramsStack = new ArrayList<>();
153 
154     /**
155      * Push a new parameter frame.
156      */
pushParamFrame()157     public final void pushParamFrame() {
158         paramsStack.add(pframe, pbase);
159         pbase = ++pframe;
160     }
161 
162     /**
163      * Pop the topmost parameter frame.
164      */
popParamFrame()165     public final void popParamFrame() {
166         if (pbase > 0) {
167             final int oldpbase = ((Integer)paramsStack.get(--pbase));
168             for (int i = pframe - 1; i >= pbase; i--) {
169                 paramsStack.remove(i);
170             }
171             pframe = pbase; pbase = oldpbase;
172         }
173     }
174 
175     /**
176      * Add a new global parameter if not already in the current frame.
177      * To setParameters of the form {http://foo.bar}xyz
178      * This needs to get mapped to an instance variable in the class
179      * The mapping  created so that
180      * the global variables in the generated class become
181      * http$colon$$flash$$flash$foo$dot$bar$colon$xyz
182      */
addParameter(String name, Object value)183     public final Object addParameter(String name, Object value) {
184         name = BasisLibrary.mapQNameToJavaName (name);
185         return addParameter(name, value, false);
186     }
187 
188     /**
189      * Add a new global or local parameter if not already in the current frame.
190      * The 'isDefault' parameter is set to true if the value passed is the
191      * default value from the <xsl:parameter> element's select attribute or
192      * element body.
193      */
addParameter(String name, Object value, boolean isDefault)194     public final Object addParameter(String name, Object value,
195         boolean isDefault)
196     {
197         // Local parameters need to be re-evaluated for each iteration
198         for (int i = pframe - 1; i >= pbase; i--) {
199             final Parameter param = (Parameter) paramsStack.get(i);
200 
201             if (param._name.equals(name)) {
202                 // Only overwrite if current value is the default value and
203                 // the new value is _NOT_ the default value.
204                 if (param._isDefault || !isDefault) {
205                     param._value = value;
206                     param._isDefault = isDefault;
207                     return value;
208                 }
209                 return param._value;
210             }
211         }
212 
213         // Add new parameter to parameter stack
214         paramsStack.add(pframe++, new Parameter(name, value, isDefault));
215         return value;
216     }
217 
218     /**
219      * Clears the parameter stack.
220      */
clearParameters()221     public void clearParameters() {
222         pbase = pframe = 0;
223         paramsStack.clear();
224     }
225 
226     /**
227      * Get the value of a parameter from the current frame or
228      * <tt>null</tt> if undefined.
229      */
getParameter(String name)230     public final Object getParameter(String name) {
231 
232         name = BasisLibrary.mapQNameToJavaName (name);
233 
234         for (int i = pframe - 1; i >= pbase; i--) {
235             final Parameter param = (Parameter)paramsStack.get(i);
236             if (param._name.equals(name)) return param._value;
237         }
238         return null;
239     }
240 
241     /************************************************************************
242      * Message handling - implementation of <xsl:message>
243      ************************************************************************/
244 
245     // Holds the translet's message handler - used for <xsl:message>.
246     // The deault message handler dumps a string stdout, but anything can be
247     // used, such as a dialog box for applets, etc.
248     private MessageHandler _msgHandler = null;
249 
250     /**
251      * Set the translet's message handler - must implement MessageHandler
252      */
setMessageHandler(MessageHandler handler)253     public final void setMessageHandler(MessageHandler handler) {
254         _msgHandler = handler;
255     }
256 
257     /**
258      * Pass a message to the message handler - used by Message class.
259      */
displayMessage(String msg)260     public final void displayMessage(String msg) {
261         if (_msgHandler == null) {
262             System.err.println(msg);
263         }
264         else {
265             _msgHandler.displayMessage(msg);
266         }
267     }
268 
269     /************************************************************************
270      * Decimal number format symbol handling
271      ************************************************************************/
272 
273     // Contains decimal number formatting symbols used by FormatNumberCall
274     public Map<String, DecimalFormat> _formatSymbols = null;
275 
276     /**
277      * Adds a DecimalFormat object to the _formatSymbols map.
278      * The entry is created with the input DecimalFormatSymbols.
279      */
addDecimalFormat(String name, DecimalFormatSymbols symbols)280     public void addDecimalFormat(String name, DecimalFormatSymbols symbols) {
281         // Instanciate map for formatting symbols if needed
282         if (_formatSymbols == null) _formatSymbols = new HashMap<>();
283 
284         // The name cannot be null - use empty string instead
285         if (name == null) name = EMPTYSTRING;
286 
287         // Construct a DecimalFormat object containing the symbols we got
288         final DecimalFormat df = new DecimalFormat();
289         if (symbols != null) {
290             df.setDecimalFormatSymbols(symbols);
291         }
292         _formatSymbols.put(name, df);
293     }
294 
295     /**
296      * Retrieves a named DecimalFormat object from the _formatSymbols map.
297      */
getDecimalFormat(String name)298     public final DecimalFormat getDecimalFormat(String name) {
299 
300         if (_formatSymbols != null) {
301             // The name cannot be null - use empty string instead
302             if (name == null) name = EMPTYSTRING;
303 
304             DecimalFormat df = _formatSymbols.get(name);
305             if (df == null) df = _formatSymbols.get(EMPTYSTRING);
306             return df;
307         }
308         return(null);
309     }
310 
311     /**
312      * Give the translet an opportunity to perform a prepass on the document
313      * to extract any information that it can store in an optimized form.
314      *
315      * Currently, it only extracts information about attributes of type ID.
316      */
prepassDocument(DOM document)317     public final void prepassDocument(DOM document) {
318         setIndexSize(document.getSize());
319         buildIDIndex(document);
320     }
321 
322     /**
323      * Leverages the Key Class to implement the XSLT id() function.
324      * buildIdIndex creates the index (##id) that Key Class uses.
325      * The index contains the element node index (int) and Id value (String).
326      */
buildIDIndex(DOM document)327     private final void buildIDIndex(DOM document) {
328         setRootForKeys(document.getDocument());
329 
330         if (document instanceof DOMEnhancedForDTM) {
331             DOMEnhancedForDTM enhancedDOM = (DOMEnhancedForDTM)document;
332 
333             // If the input source is DOMSource, the KeyIndex table is not
334             // built at this time. It will be built later by the lookupId()
335             // and containsId() methods of the KeyIndex class.
336             if (enhancedDOM.hasDOMSource()) {
337                 buildKeyIndex(ID_INDEX_NAME, document);
338                 return;
339             }
340             else {
341                 final Map<String, Integer> elementsByID = enhancedDOM.getElementsWithIDs();
342 
343                 if (elementsByID == null) {
344                     return;
345                 }
346 
347                 // Given a Map of DTM nodes indexed by ID attribute values,
348                 // loop through the table copying information to a KeyIndex
349                 // for the mapping from ID attribute value to DTM node
350                 boolean hasIDValues = false;
351                 for (Map.Entry<String, Integer> entry : elementsByID.entrySet()) {
352                     final int element = document.getNodeHandle(entry.getValue());
353                     buildKeyIndex(ID_INDEX_NAME, element, entry.getKey());
354                     hasIDValues = true;
355                 }
356 
357                 if (hasIDValues) {
358                     setKeyIndexDom(ID_INDEX_NAME, document);
359                 }
360             }
361         }
362     }
363 
364     /**
365      * After constructing the translet object, this method must be called to
366      * perform any version-specific post-initialization that's required.
367      */
postInitialization()368     public final void postInitialization() {
369         // If the version of the translet had just one namesArray, split
370         // it into multiple fields.
371         if (transletVersion < VER_SPLIT_NAMES_ARRAY) {
372             int arraySize = namesArray.length;
373             String[] newURIsArray = new String[arraySize];
374             String[] newNamesArray = new String[arraySize];
375             int[] newTypesArray = new int[arraySize];
376 
377             for (int i = 0; i < arraySize; i++) {
378                 String name = namesArray[i];
379                 int colonIndex = name.lastIndexOf(':');
380                 int lNameStartIdx = colonIndex+1;
381 
382                 if (colonIndex > -1) {
383                     newURIsArray[i] = name.substring(0, colonIndex);
384                 }
385 
386                // Distinguish attribute and element names.  Attribute has
387                // @ before local part of name.
388                if (name.charAt(lNameStartIdx) == '@') {
389                    lNameStartIdx++;
390                    newTypesArray[i] = DTM.ATTRIBUTE_NODE;
391                } else if (name.charAt(lNameStartIdx) == '?') {
392                    lNameStartIdx++;
393                    newTypesArray[i] = DTM.NAMESPACE_NODE;
394                } else {
395                    newTypesArray[i] = DTM.ELEMENT_NODE;
396                }
397                newNamesArray[i] =
398                           (lNameStartIdx == 0) ? name
399                                                : name.substring(lNameStartIdx);
400             }
401 
402             namesArray = newNamesArray;
403             urisArray  = newURIsArray;
404             typesArray = newTypesArray;
405         }
406 
407         // Was translet compiled using a more recent version of the XSLTC
408         // compiler than is known by the AbstractTranslet class?  If, so
409         // and we've made it this far (which is doubtful), we should give up.
410         if (transletVersion > CURRENT_TRANSLET_VERSION) {
411             BasisLibrary.runTimeError(BasisLibrary.UNKNOWN_TRANSLET_VERSION_ERR,
412                                       this.getClass().getName());
413         }
414     }
415 
416     /************************************************************************
417      * Index(es) for <xsl:key> / key() / id()
418      ************************************************************************/
419 
420     // Container for all indexes for xsl:key elements
421     private Map<String, KeyIndex> _keyIndexes = null;
422     private KeyIndex  _emptyKeyIndex = null;
423     private int       _indexSize = 0;
424     private int       _currentRootForKeys = 0;
425 
426     /**
427      * This method is used to pass the largest DOM size to the translet.
428      * Needed to make sure that the translet can index the whole DOM.
429      */
setIndexSize(int size)430     public void setIndexSize(int size) {
431         if (size > _indexSize) _indexSize = size;
432     }
433 
434     /**
435      * Creates a KeyIndex object of the desired size - don't want to resize!!!
436      */
createKeyIndex()437     public KeyIndex createKeyIndex() {
438         return(new KeyIndex(_indexSize));
439     }
440 
441     /**
442      * Adds a value to a key/id index
443      *   @param name is the name of the index (the key or ##id)
444      *   @param node is the node handle of the node to insert
445      *   @param value is the value that will look up the node in the given index
446      */
buildKeyIndex(String name, int node, String value)447     public void buildKeyIndex(String name, int node, String value) {
448         KeyIndex index = buildKeyIndexHelper(name);
449         index.add(value, node, _currentRootForKeys);
450     }
451 
452     /**
453      * Create an empty KeyIndex in the DOM case
454      *   @param name is the name of the index (the key or ##id)
455      *   @param dom is the DOM
456      */
buildKeyIndex(String name, DOM dom)457     public void buildKeyIndex(String name, DOM dom) {
458         KeyIndex index = buildKeyIndexHelper(name);
459         index.setDom(dom, dom.getDocument());
460     }
461 
462     /**
463      * Return KeyIndex for the buildKeyIndex methods. Note the difference from the
464      * public getKeyIndex method, this method creates a new Map if keyIndexes does
465      * not exist.
466      *
467      * @param name the name of the index (the key or ##id)
468      * @return a KeyIndex.
469      */
buildKeyIndexHelper(String name)470     private KeyIndex buildKeyIndexHelper(String name) {
471         if (_keyIndexes == null) _keyIndexes = new HashMap<>();
472 
473         KeyIndex index = _keyIndexes.get(name);
474         if (index == null) {
475             _keyIndexes.put(name, index = new KeyIndex(_indexSize));
476         }
477         return index;
478     }
479 
480     /**
481      * Returns the index for a given key (or id).
482      * The index implements our internal iterator interface
483      * @param name the name of the index (the key or ##id)
484      * @return a KeyIndex.
485      */
getKeyIndex(String name)486     public KeyIndex getKeyIndex(String name) {
487         // Return an empty key index iterator if none are defined
488         if (_keyIndexes == null) {
489             return (_emptyKeyIndex != null)
490                 ? _emptyKeyIndex
491                 : (_emptyKeyIndex = new KeyIndex(1));
492         }
493 
494         // Look up the requested key index
495         final KeyIndex index = _keyIndexes.get(name);
496 
497         // Return an empty key index iterator if the requested index not found
498         if (index == null) {
499             return (_emptyKeyIndex != null)
500                 ? _emptyKeyIndex
501                 : (_emptyKeyIndex = new KeyIndex(1));
502         }
503 
504         return(index);
505     }
506 
setRootForKeys(int root)507     private void setRootForKeys(int root) {
508         _currentRootForKeys = root;
509     }
510 
511     /**
512      * This method builds key indexes - it is overridden in the compiled
513      * translet in cases where the <xsl:key> element is used
514      */
buildKeys(DOM document, DTMAxisIterator iterator, SerializationHandler handler, int root)515     public void buildKeys(DOM document, DTMAxisIterator iterator,
516                           SerializationHandler handler,
517                           int root) throws TransletException {
518 
519     }
520 
521     /**
522      * This method builds key indexes - it is overridden in the compiled
523      * translet in cases where the <xsl:key> element is used
524      */
setKeyIndexDom(String name, DOM document)525     public void setKeyIndexDom(String name, DOM document) {
526         getKeyIndex(name).setDom(document, document.getDocument());
527     }
528 
529     /************************************************************************
530      * DOM cache handling
531      ************************************************************************/
532 
533     // Hold the DOM cache (if any) used with this translet
534     private DOMCache _domCache = null;
535 
536     /**
537      * Sets the DOM cache used for additional documents loaded using the
538      * document() function.
539      */
setDOMCache(DOMCache cache)540     public void setDOMCache(DOMCache cache) {
541         _domCache = cache;
542     }
543 
544     /**
545      * Returns the DOM cache used for this translet. Used by the LoadDocument
546      * class (if present) when the document() function is used.
547      */
getDOMCache()548     public DOMCache getDOMCache() {
549         return(_domCache);
550     }
551 
552     /************************************************************************
553      * Multiple output document extension.
554      * See compiler/TransletOutput for actual implementation.
555      ************************************************************************/
556 
openOutputHandler(String filename, boolean append)557     public SerializationHandler openOutputHandler(String filename, boolean append)
558         throws TransletException
559     {
560         try {
561             final TransletOutputHandlerFactory factory
562                 = TransletOutputHandlerFactory.newInstance(_overrideDefaultParser);
563 
564             String dirStr = new File(filename).getParent();
565             if ((null != dirStr) && (dirStr.length() > 0)) {
566                File dir = new File(dirStr);
567                dir.mkdirs();
568             }
569 
570             output = new FileOutputStream(filename, append);
571             factory.setEncoding(_encoding);
572             factory.setOutputMethod(_method);
573             factory.setOutputStream(new BufferedOutputStream(output));
574             factory.setOutputType(TransletOutputHandlerFactory.STREAM);
575 
576             final SerializationHandler handler
577                 = factory.getSerializationHandler();
578 
579             transferOutputSettings(handler);
580             handler.startDocument();
581             return handler;
582         }
583         catch (Exception e) {
584             throw new TransletException(e);
585         }
586     }
587 
openOutputHandler(String filename)588     public SerializationHandler openOutputHandler(String filename)
589        throws TransletException
590     {
591        return openOutputHandler(filename, false);
592     }
593 
closeOutputHandler(SerializationHandler handler)594     public void closeOutputHandler(SerializationHandler handler) {
595         try {
596             handler.endDocument();
597             handler.close();
598             if (output != null) {
599                 output.close();
600             }
601         }
602         catch (Exception e) {
603             // what can you do?
604         }
605     }
606 
607     /************************************************************************
608      * Native API transformation methods - _NOT_ JAXP/TrAX
609      ************************************************************************/
610 
611     /**
612      * Main transform() method - this is overridden by the compiled translet
613      */
transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler)614     public abstract void transform(DOM document, DTMAxisIterator iterator,
615                                    SerializationHandler handler)
616         throws TransletException;
617 
618     /**
619      * Calls transform() with a given output handler
620      */
transform(DOM document, SerializationHandler handler)621     public final void transform(DOM document, SerializationHandler handler)
622         throws TransletException {
623         try {
624             transform(document, document.getIterator(), handler);
625         } finally {
626             _keyIndexes = null;
627         }
628     }
629 
630     /**
631      * Used by some compiled code as a shortcut for passing strings to the
632      * output handler
633      */
characters(final String string, SerializationHandler handler)634     public final void characters(final String string,
635                                  SerializationHandler handler)
636         throws TransletException {
637         if (string != null) {
638            //final int length = string.length();
639            try {
640                handler.characters(string);
641            } catch (Exception e) {
642                throw new TransletException(e);
643            }
644         }
645     }
646 
647     /**
648      * Add's a name of an element whose text contents should be output as CDATA
649      */
addCdataElement(String name)650     public void addCdataElement(String name) {
651         if (_cdata == null) {
652             _cdata = new ArrayList<>();
653         }
654 
655         int lastColon = name.lastIndexOf(':');
656 
657         if (lastColon > 0) {
658             String uri = name.substring(0, lastColon);
659             String localName = name.substring(lastColon+1);
660             _cdata.add(uri);
661             _cdata.add(localName);
662         } else {
663             _cdata.add(null);
664             _cdata.add(name);
665         }
666     }
667 
668     /**
669      * Transfer the output settings to the output post-processor
670      */
transferOutputSettings(SerializationHandler handler)671     protected void transferOutputSettings(SerializationHandler handler) {
672         if (_method != null) {
673             if (_method.equals("xml")) {
674                 if (_standalone != null) {
675                     handler.setStandalone(_standalone);
676                 }
677                 if (_omitHeader) {
678                     handler.setOmitXMLDeclaration(true);
679                 }
680                 handler.setCdataSectionElements(_cdata);
681                 if (_version != null) {
682                     handler.setVersion(_version);
683                 }
684                 handler.setIndent(_indent);
685                 if (_indentamount >= 0)
686                     handler.setIndentAmount(_indentamount);
687                 if (_doctypeSystem != null) {
688                     handler.setDoctype(_doctypeSystem, _doctypePublic);
689                 }
690                 handler.setIsStandalone(_isStandalone);
691             }
692             else if (_method.equals("html")) {
693                 handler.setIndent(_indent);
694                 handler.setDoctype(_doctypeSystem, _doctypePublic);
695                 if (_mediaType != null) {
696                     handler.setMediaType(_mediaType);
697                 }
698             }
699         }
700         else {
701             handler.setCdataSectionElements(_cdata);
702             if (_version != null) {
703                 handler.setVersion(_version);
704             }
705             if (_standalone != null) {
706                 handler.setStandalone(_standalone);
707             }
708             if (_omitHeader) {
709                 handler.setOmitXMLDeclaration(true);
710             }
711             handler.setIndent(_indent);
712             handler.setDoctype(_doctypeSystem, _doctypePublic);
713             handler.setIsStandalone(_isStandalone);
714         }
715     }
716 
717     private Map<String, Class<?>> _auxClasses = null;
718 
addAuxiliaryClass(Class<?> auxClass)719     public void addAuxiliaryClass(Class<?> auxClass) {
720         if (_auxClasses == null) _auxClasses = new HashMap<>();
721         _auxClasses.put(auxClass.getName(), auxClass);
722     }
723 
setAuxiliaryClasses(Map<String, Class<?>> auxClasses)724     public void setAuxiliaryClasses(Map<String, Class<?>> auxClasses) {
725         _auxClasses = auxClasses;
726     }
727 
getAuxiliaryClass(String className)728     public Class<?> getAuxiliaryClass(String className) {
729         if (_auxClasses == null) return null;
730         return((Class)_auxClasses.get(className));
731     }
732 
733     // GTM added (see pg 110)
getNamesArray()734     public String[] getNamesArray() {
735         return namesArray;
736     }
737 
getUrisArray()738     public String[] getUrisArray() {
739         return urisArray;
740     }
741 
getTypesArray()742     public int[] getTypesArray() {
743         return typesArray;
744     }
745 
getNamespaceArray()746     public String[] getNamespaceArray() {
747         return namespaceArray;
748     }
749 
hasIdCall()750     public boolean hasIdCall() {
751         return _hasIdCall;
752     }
753 
getTemplates()754     public Templates getTemplates() {
755         return _templates;
756     }
757 
setTemplates(Templates templates)758     public void setTemplates(Templates templates) {
759         _templates = templates;
760     }
761     /**
762      * Return the state of the services mechanism feature.
763      */
overrideDefaultParser()764     public boolean overrideDefaultParser() {
765         return _overrideDefaultParser;
766     }
767 
768     /**
769      * Set the state of the services mechanism feature.
770      */
setOverrideDefaultParser(boolean flag)771     public void setOverrideDefaultParser(boolean flag) {
772         _overrideDefaultParser = flag;
773     }
774 
775     /**
776      * Return allowed protocols for accessing external stylesheet.
777      */
getAllowedProtocols()778     public String getAllowedProtocols() {
779         return _accessExternalStylesheet;
780     }
781 
782     /**
783      * Set allowed protocols for accessing external stylesheet.
784      */
setAllowedProtocols(String protocols)785     public void setAllowedProtocols(String protocols) {
786         _accessExternalStylesheet = protocols;
787     }
788 
789     /************************************************************************
790      * DOMImplementation caching for basis library
791      ************************************************************************/
792     protected DOMImplementation _domImplementation = null;
793 
newDocument(String uri, String qname)794     public Document newDocument(String uri, String qname)
795         throws ParserConfigurationException
796     {
797         if (_domImplementation == null) {
798             DocumentBuilderFactory dbf = JdkXmlUtils.getDOMFactory(_overrideDefaultParser);
799             _domImplementation = dbf.newDocumentBuilder().getDOMImplementation();
800         }
801         return _domImplementation.createDocument(uri, qname, null);
802     }
803 }
804