KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > Controller


1 package net.sf.saxon;
2 import net.sf.saxon.event.*;
3 import net.sf.saxon.expr.XPathContext;
4 import net.sf.saxon.expr.XPathContextMajor;
5 import net.sf.saxon.functions.Component;
6 import net.sf.saxon.instruct.*;
7 import net.sf.saxon.om.*;
8 import net.sf.saxon.tinytree.TinyBuilder;
9 import net.sf.saxon.trace.*;
10 import net.sf.saxon.trans.*;
11 import net.sf.saxon.tree.TreeBuilder;
12 import net.sf.saxon.value.DateTimeValue;
13 import org.xml.sax.SAXParseException JavaDoc;
14
15 import javax.xml.transform.*;
16 import javax.xml.transform.dom.DOMSource JavaDoc;
17 import javax.xml.transform.stream.StreamResult JavaDoc;
18 import java.io.OutputStream JavaDoc;
19 import java.io.PrintStream JavaDoc;
20 import java.util.*;
21
22 /**
23  * The Controller is Saxon's implementation of the JAXP Transformer class, and represents
24  * an executing instance of a transformation or query. Multiple concurrent executions of
25  * the same transformation or query will use different Controller instances. This class is
26  * therefore not thread-safe.
27  * <p>
28  * The Controller is serially reusable, as required by JAXP: when one transformation or query
29  * is finished, it can be used to run another. However, there is no advantage in doing this
30  * rather than allocating a new Controller each time.
31  * <p>
32  * The Controller can also be used when running Java applications that use neither XSLT nor
33  * XQuery. A dummy Controller is created when running free-standing XPath expressions.
34  * <p>
35  * The Controller holds those parts of the dynamic context that do not vary during the course
36  * of a transformation or query, or that do not change once their value has been computed.
37  * This also includes those parts of the static context that are required at run-time.
38  * <p>
39  * Wherever possible XSLT applications should use the JAXP Transformer class directly,
40  * rather than relying on Saxon-specific methods in the Controller. However, some
41  * features are currently available only through this class. This applies especially
42  * to new features specific to XSLT 2.0, since the JAXP interface still supports
43  * only XSLT 1.0. Such methods may be superseded in the future by JAXP methods.
44  * <p>
45  * Many methods on the Controller are designed for internal use and should not be
46  * considered stable. From release 8.4 onwards, those methods that are considered sufficiently
47  * stable to constitute path of the Saxon public API are labelled with the JavaDoc tag "since":
48  * the value indicates the release at which the method was added to the public API.
49  *
50  * @author Michael H. Kay
51  * @since 8.4
52  */

53
54 public class Controller extends Transformer implements InstructionInfoProvider {
55
56     private Configuration config;
57     private DocumentInfo principalSourceDocument;
58     private Bindery bindery; // holds values of global and local variables
59
private NamePool namePool;
60     private Emitter messageEmitter;
61     private RuleManager ruleManager;
62     private Properties outputProperties;
63     private GlobalParameterSet parameters;
64     private PreparedStylesheet preparedStylesheet;
65     private TraceListener traceListener;
66     private boolean tracingPaused;
67     private URIResolver standardURIResolver;
68     private URIResolver userURIResolver;
69     private Result JavaDoc principalResult;
70     private String JavaDoc principalResultURI;
71     private OutputURIResolver outputURIResolver;
72     private ErrorListener errorListener;
73     private Executable executable;
74     private int treeModel = Builder.TINY_TREE;
75     private Template initialTemplate = null;
76     private HashSet allOutputDestinations;
77     private DocumentPool sourceDocumentPool;
78     private HashMap userDataTable;
79     private DateTimeValue currentDateTime;
80     private boolean dateTimePreset = false;
81     private int initialMode = -1;
82     private NodeInfo lastRememberedNode = null;
83     private int lastRememberedNumber = -1;
84     private ClassLoader JavaDoc classLoader;
85 // private int nextLocalDocumentNumber = -1;
86

87     /**
88      * Create a Controller and initialise variables. Constructor is protected,
89      * the Controller should be created using newTransformer() in the PreparedStylesheet
90      * class.
91      *
92      * @param config The Configuration used by this Controller
93      */

94
95     public Controller(Configuration config) {
96         this.config = config;
97         // create a dummy executable
98
executable = new Executable();
99         executable.setConfiguration(config);
100         executable.setHostLanguage(config.getHostLanguage());
101         sourceDocumentPool = new DocumentPool();
102         reset();
103     }
104
105     /**
106      * Create a Controller and initialise variables. Constructor is protected,
107      * the Controller should be created using newTransformer() in the PreparedStylesheet
108      * class.
109      *
110      * @param config The Configuration used by this Controller
111      * @param executable The executable used by this Controller
112      */

113
114     public Controller(Configuration config, Executable executable) {
115         this.config = config;
116         this.executable = executable;
117         sourceDocumentPool = new DocumentPool();
118         reset();
119     }
120
121     /**
122      * <p>Reset this <code>Transformer</code> to its original configuration.</p>
123      * <p/>
124      * <p><code>Transformer</code> is reset to the same state as when it was created with
125      * {@link javax.xml.transform.TransformerFactory#newTransformer()},
126      * {@link javax.xml.transform.TransformerFactory#newTransformer(javax.xml.transform.Source source)} or
127      * {@link javax.xml.transform.Templates#newTransformer()}.
128      * <code>reset()</code> is designed to allow the reuse of existing <code>Transformer</code>s
129      * thus saving resources associated with the creation of new <code>Transformer</code>s.</p>
130      * <p>
131      * <i>The above is from the JAXP specification. With Saxon, it's unlikely that reusing a Transformer will
132      * give any performance benefits over creating a new one. The one case where it might be beneficial is
133      * to reuse the document pool (the set of documents that have been loaded using the doc() or document()
134      * functions). Therefore, this method does not clear the document pool. If you want to clear the document
135      * pool, call the method {@link #clearDocumentPool} as well.</i>
136      * <p/>
137      * <p>The reset <code>Transformer</code> is not guaranteed to have the same {@link javax.xml.transform.URIResolver}
138      * or {@link javax.xml.transform.ErrorListener} <code>Object</code>s, e.g. {@link Object#equals(Object obj)}.
139      * It is guaranteed to have a functionally equal <code>URIResolver</code>
140      * and <code>ErrorListener</code>.</p>
141      *
142      * @since 1.5
143      */

144
145     public void reset() {
146         bindery = new Bindery();
147         namePool = NamePool.getDefaultNamePool();
148         standardURIResolver = config.getSystemURIResolver();
149         userURIResolver = config.getURIResolver();
150
151         outputURIResolver = config.getOutputURIResolver();
152         errorListener = config.getErrorListener();
153         if (errorListener instanceof StandardErrorListener) {
154             // if using a standard error listener, make a fresh one
155
// for each transformation, because it is stateful - and also because the
156
// host language is now known (a Configuration can serve multiple host languages)
157
PrintStream JavaDoc ps = ((StandardErrorListener)errorListener).getErrorOutput();
158             errorListener = ((StandardErrorListener)errorListener).makeAnother(executable.getHostLanguage());
159             ((StandardErrorListener)errorListener).setErrorOutput(ps);
160             ((StandardErrorListener)errorListener).setRecoveryPolicy(
161                     config.getRecoveryPolicy());
162         }
163
164         userDataTable = new HashMap(20);
165
166         traceListener = null;
167         tracingPaused = false;
168         TraceListener tracer = config.getTraceListener();
169         if (tracer!=null) {
170             addTraceListener(tracer);
171         }
172
173         setTreeModel(config.getTreeModel());
174         principalSourceDocument = null;
175         messageEmitter = null;
176         outputProperties = null;
177         parameters = null;
178
179         principalResult = null;
180         principalResultURI = null;
181         initialTemplate = null;
182         allOutputDestinations = null;
183         currentDateTime = null;
184         dateTimePreset = false;
185         initialMode = -1;
186         lastRememberedNode = null;
187         lastRememberedNumber = -1;
188         classLoader = null;
189
190     }
191
192     /**
193      * Get the Configuration associated with this Controller. The Configuration holds
194      * settings that potentially apply globally to many different queries and transformations.
195      * @return the Configuration object
196      * @since 8.4
197      */

198     public Configuration getConfiguration() {
199         return config;
200     }
201
202     /**
203      * Set the initial mode for the transformation.
204      * <p>
205      * XSLT 2.0 allows a transformation to be started in a mode other than the default mode.
206      * The transformation then starts by looking for the template rule in this mode that best
207      * matches the initial context node.
208      * <p>
209      * This method may eventually be superseded by a standard JAXP method.
210      *
211      * @param expandedModeName the name of the initial mode. The mode is
212      * supplied as an expanded QName, that is "localname" if there is no
213      * namespace, or "{uri}localname" otherwise
214      * @since 8.4
215      */

216
217     public void setInitialMode(String JavaDoc expandedModeName) {
218         if (expandedModeName==null) return;
219         if (expandedModeName.equals("")) return;
220         initialMode = namePool.allocateClarkName(expandedModeName);
221     }
222
223     ////////////////////////////////////////////////////////////////////////////////
224
// Methods for managing output destinations and formatting
225
////////////////////////////////////////////////////////////////////////////////
226

227     /**
228      * Set the output properties for the transformation. These
229      * properties will override properties set in the templates
230      * with xsl:output.
231      * <p>
232      * As well as the properties defined in the JAXP OutputKeys class,
233      * Saxon defines an additional set of properties in {@link SaxonOutputKeys}.
234      * These fall into two categories: Constants representing serialization
235      * properties defined in XSLT 2.0 (which are not yet supported by JAXP),
236      * and constants supporting Saxon extensions to the set of serialization
237      * properties.
238      *
239      * @param properties the output properties to be used for the
240      * transformation. If the value is null, the properties are reset to
241      * be the properties of the Templates object (that is, for XSLT 2.0,
242      * the properties set in the unnamed xsl:output object).
243      * @see SaxonOutputKeys
244      * @since 8.4
245      */

246
247     public void setOutputProperties(Properties properties) {
248         if (properties == null) {
249             outputProperties = null;
250         } else {
251             Enumeration keys = properties.propertyNames();
252             while(keys.hasMoreElements()) {
253                 String JavaDoc key = (String JavaDoc)keys.nextElement();
254                 setOutputProperty(key, properties.getProperty(key));
255             }
256         }
257     }
258
259     /**
260      * Get the output properties for the transformation.
261      * <p>
262      * As well as the properties defined in the JAXP OutputKeys class,
263      * Saxon defines an additional set of properties in {@link SaxonOutputKeys}.
264      * These fall into two categories: Constants representing serialization
265      * properties defined in XSLT 2.0 (which are not yet supported by JAXP),
266      * and constants supporting Saxon extensions to the set of serialization
267      * properties.
268      *
269      * @return the output properties being used for the transformation,
270      * including properties defined in the stylesheet for the unnamed
271      * output format
272      * @see SaxonOutputKeys
273      * @since 8.4
274      */

275
276     public Properties getOutputProperties() {
277         if (outputProperties == null) {
278             if (executable==null) {
279                 return new Properties();
280             } else {
281                 outputProperties = executable.getDefaultOutputProperties();
282             }
283         }
284
285         // Make a copy, so that modifications to the returned properties have no effect
286

287         Properties newProps = new Properties();
288         Enumeration keys = outputProperties.propertyNames();
289         while(keys.hasMoreElements()) {
290             String JavaDoc key = (String JavaDoc)keys.nextElement();
291             newProps.put(key, outputProperties.getProperty(key));
292         }
293         return newProps;
294     }
295
296     /**
297      * Set an output property for the transformation.
298      * <p>
299      * As well as the properties defined in the JAXP OutputKeys class,
300      * Saxon defines an additional set of properties in {@link SaxonOutputKeys}.
301      * These fall into two categories: Constants representing serialization
302      * properties defined in XSLT 2.0 (which are not yet supported by JAXP),
303      * and constants supporting Saxon extensions to the set of serialization
304      * properties.
305      *
306      * @param name the name of the property
307      * @param value the value of the property
308      * @see SaxonOutputKeys
309      * @since 8.4
310      */

311
312     public void setOutputProperty(String JavaDoc name, String JavaDoc value) {
313         if (outputProperties == null) {
314             outputProperties = getOutputProperties();
315         }
316         try {
317             SaxonOutputKeys.checkOutputProperty(name, value);
318         } catch (DynamicError err) {
319             throw new IllegalArgumentException JavaDoc(err.getMessage());
320         }
321         outputProperties.put(name, value);
322     }
323
324     /**
325      * Get the value of an output property.
326      * <p>
327      * As well as the properties defined in the JAXP OutputKeys class,
328      * Saxon defines an additional set of properties in {@link SaxonOutputKeys}.
329      * These fall into two categories: Constants representing serialization
330      * properties defined in XSLT 2.0 (which are not yet supported by JAXP),
331      * and constants supporting Saxon extensions to the set of serialization
332      * properties.
333      *
334      * @param name the name of the requested property
335      * @return the value of the requested property
336      * @see SaxonOutputKeys
337      * @since 8.4
338      */

339
340     public String JavaDoc getOutputProperty(String JavaDoc name) {
341          try {
342             SaxonOutputKeys.checkOutputProperty(name, null);
343         } catch (DynamicError err) {
344             throw new IllegalArgumentException JavaDoc(err.getMessage());
345         }
346         if (outputProperties == null) {
347             if (executable==null) {
348                 return null;
349             } else {
350                 outputProperties = executable.getDefaultOutputProperties();
351             }
352         }
353         return outputProperties.getProperty(name);
354     }
355
356     /**
357      * Set the base output URI.
358      * This defaults to the system ID of the principal Result object, but
359      * a different value can be set for use where there is no principal result.
360      * The command line interface sets this to the current working directory.
361      * <p>
362      * The concept of the base output URI is new in XSLT 2.0: it defines the
363      * base URI for resolving relative URIs in the <code>href</code> attribute
364      * of the <code>xsl:result-document</code> instruction. This method may be
365      * superseded by a standard JAXP method when JAXP is updated to support XSLT 2.0.
366      *
367      * @param uri the base output URI
368      * @since 8.4
369      */

370
371     public void setBaseOutputURI(String JavaDoc uri) {
372         principalResultURI = uri;
373     }
374
375     /**
376      * Get the base output URI.
377      * This defaults to the system ID of the principal Result object, but
378      * a different value can be set for use where there is no principal result.
379      * The command line interface sets this to the current working directory.
380      * <p>
381      * The concept of the base output URI is new in XSLT 2.0: it defines the
382      * base URI for resolving relative URIs in the <code>href</code> attribute
383      * of the <code>xsl:result-document</code> instruction. This method may be
384      * superseded by a standard JAXP method when JAXP is updated to support XSLT 2.0.
385      *
386      * @return the base output URI
387      * @since 8.4
388      */

389
390     public String JavaDoc getBaseOutputURI() {
391         return principalResultURI;
392     }
393
394     /**
395      * Get the principal result destination.
396      * <p>
397      * This method is intended for internal use only.
398      */

399
400     public Result JavaDoc getPrincipalResult() {
401         return principalResult;
402     }
403
404     /**
405      * Check that an output destination has not been used before.
406      * <p>
407      * This method is intended for internal use only.
408      */

409
410     public boolean checkUniqueOutputDestination(String JavaDoc uri) {
411         if (allOutputDestinations == null) {
412             allOutputDestinations = new HashSet(20);
413         }
414         if (allOutputDestinations.contains(uri)) {
415             return false;
416         }
417         allOutputDestinations.add(uri);
418         return true;
419     }
420
421     ///////////////////////////////////////////////////////////////////////////////
422

423     /**
424      * Set the initial named template to be used as the entry point.
425      * <p>
426      * XSLT 2.0 allows a transformation to start by executing a named template, rather than
427      * by matching an initial context node in a source document. This method may eventually
428      * be superseded by a standard JAXP method once JAXP supports XSLT 2.0.
429      * <p>
430      * Although the Saxon command line interface does not allow both a source document and
431      * an initial template to be specified, this API has no such restriction.
432      * <p>
433      * Note that any parameters supplied using {@link #setParameter} are used as the values
434      * of global stylesheet parameters. There is no way to supply values for local parameters
435      * of the initial template.
436      *
437      * @param expandedName The expanded name of the template in {uri}local format
438      * @throws XPathException if there is no named template with this name
439      * @since 8.4
440      */

441
442     public void setInitialTemplate(String JavaDoc expandedName) throws XPathException {
443         int fingerprint = namePool.allocateClarkName(expandedName);
444         Template t = getExecutable().getNamedTemplate(fingerprint);
445         if (t == null) {
446             DynamicError err = new DynamicError("There is no named template with expanded name "
447                                            + expandedName);
448             err.setErrorCode("XTDE0040");
449             throw err;
450         } else {
451             initialTemplate = t;
452         }
453     }
454
455     ///////////////////////////////////////////////////////////////////////////////
456

457     /**
458      * Make a PipelineConfiguration based on the properties of this Controller.
459      * <p>
460      * This interface is intended primarily for internal use, although it may be necessary
461      * for applications to call it directly for use in conjunction with the experimental pull
462      * API.
463      */

464
465     public PipelineConfiguration makePipelineConfiguration() {
466         PipelineConfiguration pipe = new PipelineConfiguration();
467         pipe.setConfiguration(getConfiguration());
468         pipe.setErrorListener(getErrorListener());
469         pipe.setURIResolver(userURIResolver==null ? standardURIResolver : userURIResolver);
470         pipe.setController(this);
471         if (getExecutable() != null) {
472             // can be null for an IdentityTransformer
473
pipe.setLocationProvider(getExecutable().getLocationMap());
474         }
475         return pipe;
476     }
477
478     /**
479      * Make an Emitter to be used for xsl:message output.
480      * <p>
481      * This method is intended for internal use only.
482      *
483      * @exception XPathException if any dynamic error occurs; in
484      * particular, if the registered MessageEmitter class is not an
485      * Emitter
486      * @return The newly constructed message Emitter
487      */

488
489     public Emitter makeMessageEmitter() throws XPathException {
490         String JavaDoc emitterClass = config.getMessageEmitterClass();
491
492         Object JavaDoc emitter = config.getInstance(emitterClass, getClassLoader());
493         if (!(emitter instanceof Emitter)) {
494             throw new DynamicError(emitterClass + " is not an Emitter");
495         }
496         setMessageEmitter((Emitter)emitter);
497         return messageEmitter;
498     }
499
500     /**
501      * Set the Emitter to be used for xsl:message output.
502      * <p>
503      * Recent versions of the JAXP interface specify that by default the
504      * output of xsl:message is sent to the registered ErrorListener. Saxon
505      * does not yet implement this convention. Instead, the output is sent
506      * to a default message emitter, which is a slightly customised implementation
507      * of the standard Saxon Emitter interface.
508      * <p>
509      * This interface can be used to change the way in which Saxon outputs
510      * xsl:message output.
511      * <p>
512      * It is not necessary to use this interface in order to change the destination
513      * to which messages are written: that can be achieved by obtaining the standard
514      * message emitter and calling its {@link Emitter#setWriter} method.
515      * <p>
516      * This method is intended for use by advanced applications. The Emitter interface
517      * itself is not part of the stable Saxon public API.
518      *
519      * @param emitter The emitter to receive xsl:message output.
520      */

521
522     public void setMessageEmitter(Emitter emitter) {
523         messageEmitter = emitter;
524         messageEmitter.setPipelineConfiguration(makePipelineConfiguration());
525     }
526
527     /**
528      * Get the Emitter used for xsl:message output. This returns the emitter
529      * previously supplied to the {@link #setMessageEmitter} method, or the
530      * default message emitter otherwise.
531      *
532      * @return the Emitter being used for xsl:message output
533      */

534
535     public Emitter getMessageEmitter() {
536        return messageEmitter;
537     }
538
539     /**
540      * Make a CharacterMapExpander to handle the character map definitions in the serialization
541      * properties.
542      * <p>
543      * This method is intended for internal use only.
544      *
545      * @param useMaps the expanded use-character-maps property: a space-separated list of names
546      * of character maps to be used, each one expressed as an expanded-QName in Clark notation
547      * (that is, {uri}local-name).
548      * @return a CharacterMapExpander if one is required, or null if not (for example, if the
549      * useMaps argument is an empty string).
550      * @throws XPathException if a name in the useMaps property cannot be resolved to a declared
551      * character map.
552      */

553
554     public CharacterMapExpander makeCharacterMapExpander(String JavaDoc useMaps) throws XPathException {
555         CharacterMapExpander characterMapExpander = null;
556         HashMap characterMapIndex = getExecutable().getCharacterMapIndex();
557         if (useMaps != null && characterMapIndex != null) {
558             List characterMaps = new ArrayList(5);
559             StringTokenizer st = new StringTokenizer(useMaps);
560             while (st.hasMoreTokens()) {
561                 String JavaDoc expandedName = st.nextToken();
562                 int f = namePool.getFingerprintForExpandedName(expandedName);
563                 HashMap map = (HashMap)characterMapIndex.get(new Integer JavaDoc(f));
564                 if (map==null) {
565                     throw new DynamicError("Character map '" + expandedName + "' has not been defined");
566                 }
567                 characterMaps.add(map);
568             }
569             if (characterMaps.size() > 0) {
570                 characterMapExpander = new CharacterMapExpander();
571                 characterMapExpander.setCharacterMaps(characterMaps);
572             }
573         }
574         return characterMapExpander;
575     }
576
577     /**
578      * Get the policy for handling recoverable errors.
579      * <p>
580      * This method is intended for internal use
581      *
582      * @return the current policy. This is obtained from the error listener; if the error listener is
583      * not a StandardErrorListener, the value RECOVER_WITH_WARNINGS is returned.
584      */

585
586     public int getRecoveryPolicy() {
587         if (errorListener instanceof StandardErrorListener) {
588             return ((StandardErrorListener)errorListener).getRecoveryPolicy();
589         } else {
590             return Configuration.RECOVER_WITH_WARNINGS;
591         }
592     }
593
594     /**
595      * Set the error listener.
596      *
597      * @param listener the ErrorListener to be used
598      */

599
600     public void setErrorListener(ErrorListener listener) {
601         errorListener = listener;
602     }
603
604     /**
605      * Get the error listener.
606      *
607      * @return the ErrorListener in use
608      */

609
610     public ErrorListener getErrorListener() {
611         return errorListener;
612     }
613
614     /**
615      * Report a recoverable error. This is an XSLT concept: by default, such an error results in a warning
616      * message, and processing continues. In XQuery, however, there are no recoverable errors so a fatal
617      * error is reported.
618      * <p>
619      * This method is intended for internal use only.
620      *
621      * @param err An exception holding information about the error
622      * @exception DynamicError if the error listener decides not to
623      * recover from the error
624      */

625
626     public void recoverableError(XPathException err) throws DynamicError {
627         try {
628             if (executable.getHostLanguage() == Configuration.XQUERY) {
629                 errorListener.fatalError(err);
630                 throw err;
631             } else {
632                 errorListener.error(err);
633             }
634         } catch (TransformerException e) {
635             throw DynamicError.makeDynamicError(e);
636         }
637     }
638
639     /////////////////////////////////////////////////////////////////////////////////////////
640
// Methods for managing the various runtime control objects
641
/////////////////////////////////////////////////////////////////////////////////////////
642

643
644     /**
645      * Get the Executable object.
646      * <p>
647      * This method is intended for internal use only.
648      *
649      * @return the Executable (which represents the compiled stylesheet)
650      */

651
652     public Executable getExecutable() {
653         return executable;
654     }
655
656     /**
657      * Get the document pool. This is used only for source documents, not for stylesheet modules.
658      * <p>
659      * This method is intended for internal use only.
660      *
661      * @return the source document pool
662      */

663
664     public DocumentPool getDocumentPool() {
665         return sourceDocumentPool;
666     }
667
668     /**
669      * Clear the document pool.
670      * This is sometimes useful when re-using the same Transformer
671      * for a sequence of transformations, but it isn't done automatically, because when
672      * the transformations use common look-up documents, the caching is beneficial.
673      */

674
675     public void clearDocumentPool() {
676         sourceDocumentPool = new DocumentPool();
677     }
678
679     /**
680      * Set the principal source document (used for evaluating global variables).
681      * When a transformation is invoked using the {@link #transform} method, the
682      * principal source document is set automatically. This method is useful in XQuery,
683      * to define an initial context node for evaluating global variables, and also
684      * in XSLT 2.0, when the transformation is started by invoking a named template.
685      *
686      * @param doc The principal source document
687      * @since 8.4
688      */

689
690     public void setPrincipalSourceDocument(DocumentInfo doc) {
691         principalSourceDocument = doc;
692     }
693
694     /**
695      * Get the current bindery.
696      * <p>
697      * This method is intended for internal use only.
698      *
699      * @return the Bindery (in which values of all variables are held)
700      */

701
702     public Bindery getBindery() {
703         return bindery;
704     }
705
706     /**
707      * Get the principal source document. This returns the document
708      * previously supplied to the {@link #setPrincipalSourceDocument} method, or the
709      * principal source document set implicitly using methods such as {@link #transform}.
710      * @return the principal source document
711      * @since 8.4
712      */

713
714     public DocumentInfo getPrincipalSourceDocument() {
715         return principalSourceDocument;
716     }
717
718     /**
719      * Set an object that will be used to resolve URIs used in
720      * document(), etc.
721      *
722      * @param resolver An object that implements the URIResolver interface, or
723      * null.
724      */

725
726     public void setURIResolver(URIResolver resolver) {
727         userURIResolver = resolver;
728     }
729
730     /**
731      * Get the URI resolver.
732      *
733      * <p><i>This method changed in Saxon 8.5, to conform to the JAXP specification. If there
734      * is no user-specified URIResolver, it now returns null; previously it returned the system
735      * default URIResolver.</i></p>
736      *
737      * @return the user-supplied URI resolver if there is one, or null otherwise.
738      */

739
740     public URIResolver getURIResolver() {
741         return userURIResolver;
742     }
743
744     /**
745      * Get the fallback URI resolver. This is the URIResolver that Saxon uses when
746      * the user-supplied URI resolver returns null.
747      * <p>
748      * This method is intended for internal use only.
749      *
750      * @return the the system-defined URIResolver
751      */

752
753     public URIResolver getStandardURIResolver() {
754         return standardURIResolver;
755     }
756
757      /**
758      * Set the URI resolver for secondary output documents.
759       * <p>
760       * XSLT 2.0 introduces the <code>xsl:result-document</code instruction,
761       * allowing a transformation to have multiple result documents. JAXP does
762       * not yet support this capability. This method allows an OutputURIResolver
763       * to be specified that takes responsibility for deciding the destination
764       * (and, if it wishes, the serialization properties) of secondary output files.
765       * <p>
766       * This method may eventually be superseded by a standard JAXP method.
767      *
768      * @param resolver An object that implements the OutputURIResolver
769      * interface, or null.
770       * @since 8.4
771      */

772
773     public void setOutputURIResolver(OutputURIResolver resolver) {
774         if (resolver==null) {
775             outputURIResolver = StandardOutputResolver.getInstance();
776         } else {
777             outputURIResolver = resolver;
778         }
779     }
780
781     /**
782      * Get the output URI resolver.
783      *
784      * @return the user-supplied URI resolver if there is one, or the
785      * system-defined one otherwise.
786      * @see #setOutputURIResolver
787      * @since 8.4
788      */

789
790     public OutputURIResolver getOutputURIResolver() {
791         return outputURIResolver;
792     }
793
794     /**
795      * Get the KeyManager.
796      * <p>
797      * This method is intended for internal use only.
798      *
799      * @return the KeyManager, which holds details of all key declarations
800      */

801
802     public KeyManager getKeyManager() {
803         return executable.getKeyManager();
804     }
805
806     /**
807      * Get the name pool in use. The name pool is responsible for mapping QNames used in source
808      * documents and compiled stylesheets and queries into numeric codes. All source documents
809      * used by a given transformation or query must use the same name pool as the compiled stylesheet
810      * or query.
811      *
812      * @return the name pool in use
813      * @since 8.4
814      */

815
816     public NamePool getNamePool() {
817         return namePool;
818     }
819
820     /**
821      * Set the tree data model to use. This affects all source documents subsequently constructed using a
822      * Builder obtained from this Controller. This includes a document built from a StreamSource or
823      * SAXSource supplied as a parameter to the {@link #transform} method.
824      *
825      * @param model the required tree model: {@link Builder#STANDARD_TREE} or
826      * {@link Builder#TINY_TREE}
827      * @see net.sf.saxon.event.Builder
828      * @since 8.4
829      */

830
831     public void setTreeModel(int model) {
832         treeModel = model;
833     }
834
835     /**
836      * Make a builder for the selected tree model.
837      *
838      * @return an instance of the Builder for the chosen tree model
839      * @since 8.4
840      */

841
842     public Builder makeBuilder() {
843         Builder b;
844         if (treeModel==Builder.TINY_TREE) {
845             b = new TinyBuilder();
846         } else {
847             b = new TreeBuilder();
848         }
849         b.setTiming(config.isTiming());
850         b.setLineNumbering(config.isLineNumbering());
851         b.setPipelineConfiguration(makePipelineConfiguration());
852         return b;
853     }
854
855     /**
856      * Make a Stripper configured to implement the whitespace stripping rules.
857      * In the case of XSLT the whitespace stripping rules are normally defined
858      * by <code>xsl:strip-space</code> and <code>xsl:preserve-space</code elements
859      * in the stylesheet. Alternatively, stripping of all whitespace text nodes
860      * may be defined at the level of the Configuration, using the method
861      * {@link Configuration#setStripsAllWhiteSpace(boolean)}.
862      *
863      * @param b the Receiver to which the events filtered by this stripper are
864      * to be sent (often a Builder). May be null if the stripper is not being used for filtering
865      * into a Builder or other Receiver.
866      * @return the required Stripper. A Stripper may be used in two ways. It acts as
867      * a filter applied to an event stream, that can be used to remove the events
868      * representing whitespace text nodes before they reach a Builder. Alternatively,
869      * it can be used to define a view of an existing tree in which the whitespace
870      * text nodes are dynamically skipped while navigating the XPath axes.
871      * @since 8.4 - Generalized in 8.5 to accept any Receiver as an argument
872      */

873
874     public Stripper makeStripper(Receiver b) {
875         if (config.isStripsAllWhiteSpace()) {
876             if (b==null) {
877                 return AllElementStripper.getInstance();
878             } else {
879                 Stripper s = new AllElementStripper();
880                 s.setUnderlyingReceiver(b);
881                 return s;
882             }
883         }
884         Stripper stripper;
885         if (executable==null) {
886             stripper = new Stripper(new Mode(Mode.STRIPPER_MODE));
887         } else {
888             stripper = executable.newStripper();
889         }
890         stripper.setPipelineConfiguration(makePipelineConfiguration());
891         //stripper.setController(this);
892
if (b != null) {
893             stripper.setUnderlyingReceiver(b);
894         }
895
896         return stripper;
897     }
898
899     /**
900      * Add a document to the document pool.
901      * <p>
902      * This method is intended for internal use only.
903      *
904      * @param doc the root node of the document to be added
905      * @param systemId thesystem ID of this document
906      */

907     public void registerDocument(DocumentInfo doc, String JavaDoc systemId) {
908         sourceDocumentPool.add(doc, systemId);
909         //int nr = config.getDocumentNumberAllocator().allocateDocumentNumber();
910
}
911
912     ////////////////////////////////////////////////////////////////////////////////
913
// Methods for registering and retrieving handlers for template rules
914
////////////////////////////////////////////////////////////////////////////////
915

916     /**
917      * Set the RuleManager, used to manage template rules for each mode.
918      * <p>
919      * This method is intended for internal use only.
920      *
921      * @param r the Rule Manager
922      */

923     public void setRuleManager(RuleManager r) {
924         ruleManager = r;
925     }
926
927     /**
928      * Get the Rule Manager.
929      * <p>
930      * This method is intended for internal use only.
931      *
932      * @return the Rule Manager, used to hold details of template rules for
933      * all modes
934      */

935     public RuleManager getRuleManager() {
936         return ruleManager;
937     }
938
939     /////////////////////////////////////////////////////////////////////////
940
// Methods for tracing
941
/////////////////////////////////////////////////////////////////////////
942

943     /**
944      * Get the TraceListener. By default, there is no TraceListener, and this
945      * method returns null. A TraceListener may be added using the method
946      * {@link #addTraceListener}. If more than one TraceListener has been added,
947      * this method will return a composite TraceListener. Because this form
948      * this takes is implementation-dependent, this method is not part of the
949      * stable Saxon public API.
950      *
951      * @return the TraceListener used for XSLT or XQuery instruction tracing
952      */

953     public TraceListener getTraceListener() { // e.g.
954
return traceListener;
955     }
956
957     /**
958      * Test whether instruction execution is being traced. This will be true
959      * if (a) at least one TraceListener has been registered using the
960      * {@link #addTraceListener} method, and (b) tracing has not been temporarily
961      * paused using the {@link #pauseTracing} method.
962      *
963      * @return true if tracing is active, false otherwise
964      * @since 8.4
965      */

966
967     public final boolean isTracing() { // e.g.
968
return traceListener != null && !tracingPaused;
969     }
970
971     /**
972      * Pause or resume tracing. While tracing is paused, trace events are not sent to any
973      * of the registered TraceListeners.
974      *
975      * @param pause true if tracing is to pause; false if it is to resume
976      * @since 8.4
977      */

978     public final void pauseTracing(boolean pause) {
979         tracingPaused = pause;
980     }
981
982     /**
983      * Adds the specified trace listener to receive trace events from
984      * this instance. Note that although TraceListeners can be added
985      * or removed dynamically, this has no effect unless the stylesheet
986      * or query has been compiled with tracing enabled. This is achieved
987      * by calling {@link Configuration#setTraceListener} or by setting
988      * the attribute {@link FeatureKeys#TRACE_LISTENER} on the
989      * TransformerFactory. Conversely, if this property has been set in the
990      * Configuration or TransformerFactory, the TraceListener will automatically
991      * be added to every Controller that uses that Configuration.
992      *
993      * @param trace the trace listener.
994      * @since 8.4
995      */

996
997     public void addTraceListener(TraceListener trace) { // e.g.
998
traceListener = TraceEventMulticaster.add(traceListener, trace);
999     }
1000
1001    /**
1002     * Removes the specified trace listener so that the listener will no longer
1003     * receive trace events.
1004     *
1005     * @param trace the trace listener.
1006     * @since 8.4
1007&