View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * 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   * $Id: AbstractTranslet.java,v 1.6 2006/06/19 19:49:03 spericas Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.runtime;
25  
26  import com.sun.org.apache.xalan.internal.XalanConstants;
27  import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
28  import java.io.File;
29  import java.io.FileOutputStream;
30  import java.io.BufferedOutputStream;
31  import java.text.DecimalFormat;
32  import java.text.DecimalFormatSymbols;
33  import java.util.ArrayList;
34  import java.util.Enumeration;
35  import java.util.Vector;
36  import javax.xml.transform.Templates;
37  import javax.xml.parsers.DocumentBuilderFactory;
38  import org.w3c.dom.Document;
39  import org.w3c.dom.DOMImplementation;
40  import javax.xml.parsers.ParserConfigurationException;
41  
42  import com.sun.org.apache.xml.internal.dtm.DTM;
43  
44  import com.sun.org.apache.xalan.internal.xsltc.DOM;
45  import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
46  import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
47  import com.sun.org.apache.xalan.internal.xsltc.Translet;
48  import com.sun.org.apache.xalan.internal.xsltc.TransletException;
49  import com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter;
50  import com.sun.org.apache.xalan.internal.xsltc.dom.KeyIndex;
51  import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
52  import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
53  import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
54  
55  /**
56   * @author Jacek Ambroziak
57   * @author Santiago Pericas-Geertsen
58   * @author Morten Jorgensen
59   * @author G. Todd Miller
60   * @author John Howard, JohnH@schemasoft.com
61   */
62  public abstract class AbstractTranslet implements Translet {
63  
64      // These attributes are extracted from the xsl:output element. They also
65      // appear as fields (with the same type, only public) in Output.java
66      public String  _version = "1.0";
67      public String  _method = null;
68      public String  _encoding = "UTF-8";
69      public boolean _omitHeader = false;
70      public String  _standalone = null;
71      //see OutputPropertiesFactory.ORACLE_IS_STANDALONE
72      public boolean  _isStandalone = false;
73      public String  _doctypePublic = null;
74      public String  _doctypeSystem = null;
75      public boolean _indent = false;
76      public String  _mediaType = null;
77      public Vector _cdata = null;
78      public int _indentamount = -1;
79  
80      public static final int FIRST_TRANSLET_VERSION = 100;
81      public static final int VER_SPLIT_NAMES_ARRAY = 101;
82      public static final int CURRENT_TRANSLET_VERSION = VER_SPLIT_NAMES_ARRAY;
83  
84      // Initialize Translet version field to base value.  A class that extends
85      // AbstractTranslet may override this value to a more recent translet
86      // version; if it doesn't override the value (because it was compiled
87      // before the notion of a translet version was introduced, it will get
88      // this default value).
89      protected int transletVersion = FIRST_TRANSLET_VERSION;
90  
91      // DOM/translet handshaking - the arrays are set by the compiled translet
92      protected String[] namesArray;
93      protected String[] urisArray;
94      protected int[]    typesArray;
95      protected String[] namespaceArray;
96  
97      // The Templates object that is used to create this Translet instance
98      protected Templates _templates = null;
99  
100     // Boolean flag to indicate whether this translet has id functions.
101     protected boolean _hasIdCall = false;
102 
103     // TODO - these should only be instanciated when needed
104     protected StringValueHandler stringValueHandler = new StringValueHandler();
105 
106     // Use one empty string instead of constantly instanciating String("");
107     private final static String EMPTYSTRING = "";
108 
109     // This is the name of the index used for ID attributes
110     private final static String ID_INDEX_NAME = "##id";
111 
112     private boolean _useServicesMechanism;
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      ************************************************************************/
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      */
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 ArrayList paramsStack = new ArrayList();
153 
154     /**
155      * Push a new parameter frame.
156      */
157     public final void pushParamFrame() {
158         paramsStack.add(pframe, new Integer(pbase));
159         pbase = ++pframe;
160     }
161 
162     /**
163      * Pop the topmost parameter frame.
164      */
165     public final void popParamFrame() {
166         if (pbase > 0) {
167             final int oldpbase = ((Integer)paramsStack.get(--pbase)).intValue();
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      */
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      */
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      */
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      */
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      */
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      */
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 Hashtable _formatSymbols = null;
275 
276     /**
277      * Adds a DecimalFormat object to the _formatSymbols hashtable.
278      * The entry is created with the input DecimalFormatSymbols.
279      */
280     public void addDecimalFormat(String name, DecimalFormatSymbols symbols) {
281         // Instanciate hashtable for formatting symbols if needed
282         if (_formatSymbols == null) _formatSymbols = new Hashtable();
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 _formatSymbols hashtable.
297      */
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 = (DecimalFormat)_formatSymbols.get(name);
305             if (df == null) df = (DecimalFormat)_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      */
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      */
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 Hashtable elementsByID = enhancedDOM.getElementsWithIDs();
342 
343                 if (elementsByID == null) {
344                     return;
345                 }
346 
347                 // Given a Hashtable 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                 final Enumeration idValues = elementsByID.keys();
351                 boolean hasIDValues = false;
352 
353                 while (idValues.hasMoreElements()) {
354                     final Object idValue = idValues.nextElement();
355                     final int element =
356                             document.getNodeHandle(
357                                         ((Integer)elementsByID.get(idValue))
358                                                 .intValue());
359 
360                     buildKeyIndex(ID_INDEX_NAME, element, idValue);
361                     hasIDValues = true;
362                 }
363 
364                 if (hasIDValues) {
365                     setKeyIndexDom(ID_INDEX_NAME, document);
366                 }
367             }
368         }
369     }
370 
371     /**
372      * After constructing the translet object, this method must be called to
373      * perform any version-specific post-initialization that's required.
374      */
375     public final void postInitialization() {
376         // If the version of the translet had just one namesArray, split
377         // it into multiple fields.
378         if (transletVersion < VER_SPLIT_NAMES_ARRAY) {
379             int arraySize = namesArray.length;
380             String[] newURIsArray = new String[arraySize];
381             String[] newNamesArray = new String[arraySize];
382             int[] newTypesArray = new int[arraySize];
383 
384             for (int i = 0; i < arraySize; i++) {
385                 String name = namesArray[i];
386                 int colonIndex = name.lastIndexOf(':');
387                 int lNameStartIdx = colonIndex+1;
388 
389                 if (colonIndex > -1) {
390                     newURIsArray[i] = name.substring(0, colonIndex);
391                 }
392 
393                // Distinguish attribute and element names.  Attribute has
394                // @ before local part of name.
395                if (name.charAt(lNameStartIdx) == '@') {
396                    lNameStartIdx++;
397                    newTypesArray[i] = DTM.ATTRIBUTE_NODE;
398                } else if (name.charAt(lNameStartIdx) == '?') {
399                    lNameStartIdx++;
400                    newTypesArray[i] = DTM.NAMESPACE_NODE;
401                } else {
402                    newTypesArray[i] = DTM.ELEMENT_NODE;
403                }
404                newNamesArray[i] =
405                           (lNameStartIdx == 0) ? name
406                                                : name.substring(lNameStartIdx);
407             }
408 
409             namesArray = newNamesArray;
410             urisArray  = newURIsArray;
411             typesArray = newTypesArray;
412         }
413 
414         // Was translet compiled using a more recent version of the XSLTC
415         // compiler than is known by the AbstractTranslet class?  If, so
416         // and we've made it this far (which is doubtful), we should give up.
417         if (transletVersion > CURRENT_TRANSLET_VERSION) {
418             BasisLibrary.runTimeError(BasisLibrary.UNKNOWN_TRANSLET_VERSION_ERR,
419                                       this.getClass().getName());
420         }
421     }
422 
423     /************************************************************************
424      * Index(es) for <xsl:key> / key() / id()
425      ************************************************************************/
426 
427     // Container for all indexes for xsl:key elements
428     private Hashtable _keyIndexes = null;
429     private KeyIndex  _emptyKeyIndex = null;
430     private int       _indexSize = 0;
431     private int       _currentRootForKeys = 0;
432 
433     /**
434      * This method is used to pass the largest DOM size to the translet.
435      * Needed to make sure that the translet can index the whole DOM.
436      */
437     public void setIndexSize(int size) {
438         if (size > _indexSize) _indexSize = size;
439     }
440 
441     /**
442      * Creates a KeyIndex object of the desired size - don't want to resize!!!
443      */
444     public KeyIndex createKeyIndex() {
445         return(new KeyIndex(_indexSize));
446     }
447 
448     /**
449      * Adds a value to a key/id index
450      *   @param name is the name of the index (the key or ##id)
451      *   @param node is the node handle of the node to insert
452      *   @param value is the value that will look up the node in the given index
453      */
454     public void buildKeyIndex(String name, int node, Object value) {
455         if (_keyIndexes == null) _keyIndexes = new Hashtable();
456 
457         KeyIndex index = (KeyIndex)_keyIndexes.get(name);
458         if (index == null) {
459             _keyIndexes.put(name, index = new KeyIndex(_indexSize));
460         }
461         index.add(value, node, _currentRootForKeys);
462     }
463 
464     /**
465      * Create an empty KeyIndex in the DOM case
466      *   @param name is the name of the index (the key or ##id)
467      *   @param dom is the DOM
468      */
469     public void buildKeyIndex(String name, DOM dom) {
470         if (_keyIndexes == null) _keyIndexes = new Hashtable();
471 
472         KeyIndex index = (KeyIndex)_keyIndexes.get(name);
473         if (index == null) {
474             _keyIndexes.put(name, index = new KeyIndex(_indexSize));
475         }
476         index.setDom(dom, dom.getDocument());
477     }
478 
479     /**
480      * Returns the index for a given key (or id).
481      * The index implements our internal iterator interface
482      */
483     public KeyIndex getKeyIndex(String name) {
484         // Return an empty key index iterator if none are defined
485         if (_keyIndexes == null) {
486             return (_emptyKeyIndex != null)
487                 ? _emptyKeyIndex
488                 : (_emptyKeyIndex = new KeyIndex(1));
489         }
490 
491         // Look up the requested key index
492         final KeyIndex index = (KeyIndex)_keyIndexes.get(name);
493 
494         // Return an empty key index iterator if the requested index not found
495         if (index == null) {
496             return (_emptyKeyIndex != null)
497                 ? _emptyKeyIndex
498                 : (_emptyKeyIndex = new KeyIndex(1));
499         }
500 
501         return(index);
502     }
503 
504     private void setRootForKeys(int root) {
505         _currentRootForKeys = root;
506     }
507 
508     /**
509      * This method builds key indexes - it is overridden in the compiled
510      * translet in cases where the <xsl:key> element is used
511      */
512     public void buildKeys(DOM document, DTMAxisIterator iterator,
513                           SerializationHandler handler,
514                           int root) throws TransletException {
515 
516     }
517 
518     /**
519      * This method builds key indexes - it is overridden in the compiled
520      * translet in cases where the <xsl:key> element is used
521      */
522     public void setKeyIndexDom(String name, DOM document) {
523         getKeyIndex(name).setDom(document, document.getDocument());
524     }
525 
526     /************************************************************************
527      * DOM cache handling
528      ************************************************************************/
529 
530     // Hold the DOM cache (if any) used with this translet
531     private DOMCache _domCache = null;
532 
533     /**
534      * Sets the DOM cache used for additional documents loaded using the
535      * document() function.
536      */
537     public void setDOMCache(DOMCache cache) {
538         _domCache = cache;
539     }
540 
541     /**
542      * Returns the DOM cache used for this translet. Used by the LoadDocument
543      * class (if present) when the document() function is used.
544      */
545     public DOMCache getDOMCache() {
546         return(_domCache);
547     }
548 
549     /************************************************************************
550      * Multiple output document extension.
551      * See compiler/TransletOutput for actual implementation.
552      ************************************************************************/
553 
554     public SerializationHandler openOutputHandler(String filename, boolean append)
555         throws TransletException
556     {
557         try {
558             final TransletOutputHandlerFactory factory
559                 = TransletOutputHandlerFactory.newInstance();
560 
561             String dirStr = new File(filename).getParent();
562             if ((null != dirStr) && (dirStr.length() > 0)) {
563                File dir = new File(dirStr);
564                dir.mkdirs();
565             }
566 
567             factory.setEncoding(_encoding);
568             factory.setOutputMethod(_method);
569             factory.setOutputStream(new BufferedOutputStream(new FileOutputStream(filename, append)));
570             factory.setOutputType(TransletOutputHandlerFactory.STREAM);
571 
572             final SerializationHandler handler
573                 = factory.getSerializationHandler();
574 
575             transferOutputSettings(handler);
576             handler.startDocument();
577             return handler;
578         }
579         catch (Exception e) {
580             throw new TransletException(e);
581         }
582     }
583 
584     public SerializationHandler openOutputHandler(String filename)
585        throws TransletException
586     {
587        return openOutputHandler(filename, false);
588     }
589 
590     public void closeOutputHandler(SerializationHandler handler) {
591         try {
592             handler.endDocument();
593             handler.close();
594         }
595         catch (Exception e) {
596             // what can you do?
597         }
598     }
599 
600     /************************************************************************
601      * Native API transformation methods - _NOT_ JAXP/TrAX
602      ************************************************************************/
603 
604     /**
605      * Main transform() method - this is overridden by the compiled translet
606      */
607     public abstract void transform(DOM document, DTMAxisIterator iterator,
608                                    SerializationHandler handler)
609         throws TransletException;
610 
611     /**
612      * Calls transform() with a given output handler
613      */
614     public final void transform(DOM document, SerializationHandler handler)
615         throws TransletException {
616         try {
617             transform(document, document.getIterator(), handler);
618         } finally {
619             _keyIndexes = null;
620         }
621     }
622 
623     /**
624      * Used by some compiled code as a shortcut for passing strings to the
625      * output handler
626      */
627     public final void characters(final String string,
628                                  SerializationHandler handler)
629         throws TransletException {
630         if (string != null) {
631            //final int length = string.length();
632            try {
633                handler.characters(string);
634            } catch (Exception e) {
635                throw new TransletException(e);
636            }
637         }
638     }
639 
640     /**
641      * Add's a name of an element whose text contents should be output as CDATA
642      */
643     public void addCdataElement(String name) {
644         if (_cdata == null) {
645             _cdata = new Vector();
646         }
647 
648         int lastColon = name.lastIndexOf(':');
649 
650         if (lastColon > 0) {
651             String uri = name.substring(0, lastColon);
652             String localName = name.substring(lastColon+1);
653             _cdata.addElement(uri);
654             _cdata.addElement(localName);
655         } else {
656             _cdata.addElement(null);
657             _cdata.addElement(name);
658         }
659     }
660 
661     /**
662      * Transfer the output settings to the output post-processor
663      */
664     protected void transferOutputSettings(SerializationHandler handler) {
665         if (_method != null) {
666             if (_method.equals("xml")) {
667                 if (_standalone != null) {
668                     handler.setStandalone(_standalone);
669                 }
670                 if (_omitHeader) {
671                     handler.setOmitXMLDeclaration(true);
672                 }
673                 handler.setCdataSectionElements(_cdata);
674                 if (_version != null) {
675                     handler.setVersion(_version);
676                 }
677                 handler.setIndent(_indent);
678                 handler.setIndentAmount(_indentamount);
679                 if (_doctypeSystem != null) {
680                     handler.setDoctype(_doctypeSystem, _doctypePublic);
681                 }
682                 handler.setIsStandalone(_isStandalone);
683             }
684             else if (_method.equals("html")) {
685                 handler.setIndent(_indent);
686                 handler.setDoctype(_doctypeSystem, _doctypePublic);
687                 if (_mediaType != null) {
688                     handler.setMediaType(_mediaType);
689                 }
690             }
691         }
692         else {
693             handler.setCdataSectionElements(_cdata);
694             if (_version != null) {
695                 handler.setVersion(_version);
696             }
697             if (_standalone != null) {
698                 handler.setStandalone(_standalone);
699             }
700             if (_omitHeader) {
701                 handler.setOmitXMLDeclaration(true);
702             }
703             handler.setIndent(_indent);
704             handler.setDoctype(_doctypeSystem, _doctypePublic);
705             handler.setIsStandalone(_isStandalone);
706         }
707     }
708 
709     private Hashtable _auxClasses = null;
710 
711     public void addAuxiliaryClass(Class auxClass) {
712         if (_auxClasses == null) _auxClasses = new Hashtable();
713         _auxClasses.put(auxClass.getName(), auxClass);
714     }
715 
716     public void setAuxiliaryClasses(Hashtable auxClasses) {
717         _auxClasses = auxClasses;
718     }
719 
720     public Class getAuxiliaryClass(String className) {
721         if (_auxClasses == null) return null;
722         return((Class)_auxClasses.get(className));
723     }
724 
725     // GTM added (see pg 110)
726     public String[] getNamesArray() {
727         return namesArray;
728     }
729 
730     public String[] getUrisArray() {
731         return urisArray;
732     }
733 
734     public int[] getTypesArray() {
735         return typesArray;
736     }
737 
738     public String[] getNamespaceArray() {
739         return namespaceArray;
740     }
741 
742     public boolean hasIdCall() {
743         return _hasIdCall;
744     }
745 
746     public Templates getTemplates() {
747         return _templates;
748     }
749 
750     public void setTemplates(Templates templates) {
751         _templates = templates;
752     }
753     /**
754      * Return the state of the services mechanism feature.
755      */
756     public boolean useServicesMechnism() {
757         return _useServicesMechanism;
758     }
759 
760     /**
761      * Set the state of the services mechanism feature.
762      */
763     public void setServicesMechnism(boolean flag) {
764         _useServicesMechanism = flag;
765     }
766 
767     /**
768      * Return allowed protocols for accessing external stylesheet.
769      */
770     public String getAllowedProtocols() {
771         return _accessExternalStylesheet;
772     }
773 
774     /**
775      * Set allowed protocols for accessing external stylesheet.
776      */
777     public void setAllowedProtocols(String protocols) {
778         _accessExternalStylesheet = protocols;
779     }
780 
781     /************************************************************************
782      * DOMImplementation caching for basis library
783      ************************************************************************/
784     protected DOMImplementation _domImplementation = null;
785 
786     public Document newDocument(String uri, String qname)
787         throws ParserConfigurationException
788     {
789         if (_domImplementation == null) {
790             DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(_useServicesMechanism);
791             _domImplementation = dbf.newDocumentBuilder().getDOMImplementation();
792         }
793         return _domImplementation.createDocument(uri, qname, null);
794     }
795 }