KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > transformation > TraxTransformer


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.cocoon.transformation;
18
19 import java.io.IOException JavaDoc;
20 import java.io.Serializable JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.util.Enumeration JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.Set JavaDoc;
27 import java.util.Map.Entry;
28
29 import javax.xml.transform.sax.SAXResult JavaDoc;
30 import javax.xml.transform.sax.TransformerHandler JavaDoc;
31
32 import org.apache.avalon.framework.activity.Disposable;
33 import org.apache.avalon.framework.configuration.Configurable;
34 import org.apache.avalon.framework.configuration.Configuration;
35 import org.apache.avalon.framework.configuration.ConfigurationException;
36 import org.apache.avalon.framework.logger.LogEnabled;
37 import org.apache.avalon.framework.parameters.Parameters;
38 import org.apache.avalon.framework.service.ServiceException;
39 import org.apache.avalon.framework.service.ServiceManager;
40 import org.apache.avalon.framework.service.Serviceable;
41 import org.apache.cocoon.ProcessingException;
42 import org.apache.cocoon.caching.CacheableProcessingComponent;
43 import org.apache.cocoon.components.source.SourceUtil;
44 import org.apache.cocoon.components.xslt.TraxErrorListener;
45 import org.apache.cocoon.environment.Cookie;
46 import org.apache.cocoon.environment.ObjectModelHelper;
47 import org.apache.cocoon.environment.Request;
48 import org.apache.cocoon.environment.Session;
49 import org.apache.cocoon.environment.SourceResolver;
50 import org.apache.cocoon.xml.XMLConsumer;
51 import org.apache.commons.lang.BooleanUtils;
52 import org.apache.commons.lang.exception.NestableRuntimeException;
53 import org.apache.excalibur.source.Source;
54 import org.apache.excalibur.source.SourceException;
55 import org.apache.excalibur.source.SourceValidity;
56 import org.apache.excalibur.xml.xslt.XSLTProcessor;
57 import org.apache.excalibur.xml.xslt.XSLTProcessorException;
58 import org.xml.sax.SAXException JavaDoc;
59
60 /**
61  * @cocoon.sitemap.component.documentation
62  * The stylesheet processor
63  *
64  * @cocoon.sitemap.component.name xslt
65  * @cocoon.sitemap.component.logger sitemap.transformer.xslt
66  * @cocoon.sitemap.component.documentation.caching
67  * Uses the last modification date of the xslt document for validation
68  *
69  * @cocoon.sitemap.component.pooling.max 32
70  * <p>
71  * This Transformer is used to transform the incoming SAX stream using
72  * a TrAXProcessor. Use the following sitemap declarations to define, configure
73  * and parameterize it:
74  * </p>
75  * <b>In the map:sitemap/map:components/map:transformers:</b><br>
76  * <pre>
77  * &lt;map:transformer name="xslt" SRC="org.apache.cocoon.transformation.TraxTransformer"&gt;<br>
78  * &lt;use-request-parameters&gt;false&lt;/use-request-parameters&gt;
79  * &lt;use-browser-capabilities-db&gt;false&lt;/use-browser-capabilities-db&gt;
80  * &lt;use-session-info&gt;false&lt;/use-session-info&gt;
81  * &lt;xslt-processor-role&gt;xslt&lt;/xslt-processor-role&gt;
82  * &lt;transformer-factory&gt;org.apache.xalan.processor.TransformerFactoryImpl&lt;/transformer-factory&gt;
83  * &lt;check-includes&gt;true&lt;/check-includes&gt;
84  * &lt;/map:transformer&gt;
85  * </pre>
86  *
87  * The &lt;use-request-parameter&gt; configuration forces the transformer to make all
88  * request parameters available in the XSLT stylesheet. Note that this has
89  * implications for caching of the generated output of this transformer.<br>
90  * This property is false by default.
91  * <p>
92  * The &lt;use-cookies&gt; configuration forces the transformer to make all
93  * cookies from the request available in the XSLT stylesheets.
94  * Note that this has implications for caching of the generated output of this
95  * transformer.<br>
96  * This property is false by default.
97  * <p>
98  * The &lt;use-session-info&gt; configuration forces the transformer to make all
99  * of the session information available in the XSLT stylesheetas.<br>
100  * These infos are (boolean values are "true" or "false" strings: session-is-new,
101  * session-id-from-cookie, session-id-from-url, session-valid, session-id.<br>
102  * This property is false by default.
103  *
104  * <p>Note that this has implications for caching of the generated output of
105  * this transformer.<br>
106  *
107  *
108  * The &lt;xslt-processor-role&gt; configuration allows to specify the TrAX processor (defined in
109  * the cocoon.xconf) that will be used to obtain the XSLT processor. This allows to have
110  * several XSLT processors in the configuration (e.g. Xalan, XSLTC, Saxon, ...) and choose
111  * one or the other depending on the needs of stylesheet specificities.<br>
112  * If no processor is specified, this transformer will use the XSLT implementation
113  * that Cocoon uses internally.
114  *
115  * The &lt;transformer-factory&gt; configuration allows to specify the TrAX transformer factory
116  * implementation that will be used to obtain the XSLT processor. This is only useful for
117  * compatibility reasons. Please configure the XSLT processor in the cocoon.xconf properly
118  * and use the xslt-processor-role configuration mentioned above.
119  *
120  * The &lt;check-includes&gt; configuration specifies if the included stylesheets are
121  * also checked for changes during caching. If this is set to true (default), the
122  * included stylesheets are also checked for changes; if this is set to false, only
123  * the main stylesheet is checked. Setting this to false improves the performance,
124  * and should be used whenever no includes are in the stylesheet. However, if
125  * you have includes, you have to be careful when changing included stylesheets
126  * as the changes might not take effect immediately. You should touch the main
127  * stylesheet as well.
128  *
129  * <p>
130  * <b>In a map:sitemap/map:pipelines/map:pipeline:</b><br>
131  * <pre>
132  * &lt;map:transform type="xslt" SRC="stylesheets/yours.xsl"&gt;<br>
133  * &lt;parameter name="myparam" value="myvalue"/&gt;
134  * &lt;/map:transform&gt;
135  * </pre>
136  * All &lt;parameter&gt; declarations will be made available in the XSLT stylesheet as
137  * xsl:variables.
138  *
139  * @author <a HREF="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
140  * @author <a HREF="mailto:dims@yahoo.com">Davanum Srinivas</a>
141  * @author <a HREF="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
142  * @author <a HREF="mailto:giacomo@apache.org">Giacomo Pati</a>
143  * @author <a HREF="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
144  * @author <a HREF="mailto:marbut@hplb.hpl.hp.com">Mark H. Butler</a>
145  * @author <a HREF="mailto:stefano@apache.org">Stefano Mazzocchi</a>
146  *
147  * @version SVN $Id: TraxTransformer.java 326716 2005-10-19 21:44:41Z sylvain $
148  */

149 public class TraxTransformer extends AbstractTransformer
150 implements Serviceable, Configurable, CacheableProcessingComponent, Disposable {
151
152     /** The service manager instance (protected because used by subclasses) */
153     protected ServiceManager manager;
154
155     /** The object model (protected because used by subclasses) */
156     protected Map JavaDoc objectModel;
157
158     /** Logicsheet parameters (protected because used by subclasses) */
159     protected Map JavaDoc logicSheetParameters;
160
161     /** Should we make the request parameters available in the stylesheet? (default is off) */
162     private boolean useParameters = false;
163     private boolean _useParameters = false;
164
165     /** Should we make the cookies available in the stylesheet? (default is off) */
166     private boolean useCookies = false;
167     private boolean _useCookies = false;
168
169     /** Should we info about the session available in the stylesheet? (default is off) */
170     private boolean useSessionInfo = false;
171     private boolean _useSessionInfo = false;
172
173     /** Do we check included stylesheets for changes? */
174     private boolean checkIncludes = true;
175
176     /** The trax TransformerHandler */
177     protected TransformerHandler JavaDoc transformerHandler;
178
179     /** The validity of the Transformer */
180     protected SourceValidity transformerValidity;
181
182     /** The Source */
183     private Source inputSource;
184     /** The parameters */
185     private Parameters par;
186     /** The source resolver */
187     private SourceResolver resolver;
188
189     /** Default source, used to create specialized transformers by configuration */
190     private String JavaDoc defaultSrc;
191
192     /** The XSLTProcessor */
193     private XSLTProcessor xsltProcessor;
194
195     /** Did we finish the processing (is endDocument() called) */
196     private boolean finishedDocument = false;
197
198     /** Xalan's DTMManager.getIncremental() method. See recycle() method to see what we need this for. */
199     private Method JavaDoc xalanDtmManagerGetIncrementalMethod;
200
201     /** Exception that might occur during setConsumer */
202     private SAXException JavaDoc exceptionDuringSetConsumer;
203
204     /** The error listener used by the stylesheet */
205     private TraxErrorListener errorListener;
206
207     /**
208      * Configure this transformer.
209      */

210     public void configure(Configuration conf)
211     throws ConfigurationException {
212         Configuration child;
213
214         child = conf.getChild("use-request-parameters");
215         this.useParameters = child.getValueAsBoolean(false);
216         this._useParameters = this.useParameters;
217
218         child = conf.getChild("use-cookies");
219         this.useCookies = child.getValueAsBoolean(false);
220         this._useCookies = this.useCookies;
221
222         child = conf.getChild("use-session-info");
223         this.useSessionInfo = child.getValueAsBoolean(false);
224         this._useSessionInfo = this.useSessionInfo;
225
226         child = conf.getChild("transformer-factory");
227         // traxFactory is null, if transformer-factory config is unspecified
228
final String JavaDoc traxFactory = child.getValue(null);
229
230         child = conf.getChild("xslt-processor-role");
231         String JavaDoc xsltProcessorRole = child.getValue(XSLTProcessor.ROLE);
232         if (!xsltProcessorRole.startsWith(XSLTProcessor.ROLE)) {
233             xsltProcessorRole = XSLTProcessor.ROLE + '/' + xsltProcessorRole;
234         }
235
236         child = conf.getChild("check-includes");
237         this.checkIncludes = child.getValueAsBoolean(this.checkIncludes);
238
239         child = conf.getChild("default-src",false);
240         if(child!=null) {
241             this.defaultSrc = child.getValue();
242         }
243
244         if (getLogger().isDebugEnabled()) {
245             getLogger().debug("Use parameters is " + this.useParameters);
246             getLogger().debug("Use cookies is " + this.useCookies);
247             getLogger().debug("Use session info is " + this.useSessionInfo);
248             getLogger().debug("Use TrAX Processor " + xsltProcessorRole);
249             getLogger().debug("Check for included stylesheets is " + this.checkIncludes);
250             if (traxFactory != null) {
251                 getLogger().debug("Use TrAX Transformer Factory " + traxFactory);
252             } else {
253                 getLogger().debug("Use default TrAX Transformer Factory.");
254             }
255             getLogger().debug("Default source = " + this.defaultSrc);
256         }
257
258         try {
259             this.xsltProcessor = (XSLTProcessor) this.manager.lookup(xsltProcessorRole);
260             if (traxFactory != null) {
261                 this.xsltProcessor.setTransformerFactory(traxFactory);
262             }
263         } catch (ServiceException e) {
264             throw new ConfigurationException("Cannot load XSLT processor", e);
265         }
266
267         try {
268             // see the recyle() method to see what we need this for
269
Class JavaDoc dtmManagerClass = Class.forName("org.apache.xml.dtm.DTMManager");
270             xalanDtmManagerGetIncrementalMethod = dtmManagerClass.getMethod("getIncremental", null);
271         } catch (ClassNotFoundException JavaDoc e) {
272             // do nothing -- user does not use xalan, so we don't need the dtm manager
273
} catch (NoSuchMethodException JavaDoc e) {
274             throw new ConfigurationException("Was not able to get getIncremental method from Xalan's DTMManager.", e);
275         }
276     }
277
278     /**
279      * Set the current <code>ServiceManager</code> instance used by this
280      * <code>Serviceable</code>.
281      */

282     public void service(ServiceManager manager) throws ServiceException {
283         this.manager = manager;
284     }
285
286     /**
287      * Set the <code>SourceResolver</code>, the <code>Map</code> with
288      * the object model, the source and sitemap
289      * <code>Parameters</code> used to process the request.
290      */

291     public void setup(SourceResolver resolver, Map JavaDoc objectModel, String JavaDoc src, Parameters par)
292     throws SAXException JavaDoc, ProcessingException, IOException JavaDoc {
293
294         if(src==null && defaultSrc!=null) {
295             if(getLogger().isDebugEnabled()) {
296                 getLogger().debug("src is null, using default source " + defaultSrc);
297             }
298             src = defaultSrc;
299         }
300
301         if (src == null) {
302             throw new ProcessingException("Stylesheet URI can't be null");
303         }
304
305         this.par = par;
306         this.objectModel = objectModel;
307         this.resolver = resolver;
308         try {
309             this.inputSource = resolver.resolveURI(src);
310         } catch (SourceException se) {
311             throw SourceUtil.handle("Unable to resolve " + src, se);
312         }
313         _useParameters = par.getParameterAsBoolean("use-request-parameters", this.useParameters);
314         _useCookies = par.getParameterAsBoolean("use-cookies", this.useCookies);
315         _useSessionInfo = par.getParameterAsBoolean("use-session-info", this.useSessionInfo);
316         final boolean _checkIncludes = par.getParameterAsBoolean("check-includes", this.checkIncludes);
317
318         if (getLogger().isDebugEnabled()) {
319             getLogger().debug("Using stylesheet: '" + this.inputSource.getURI() + "' in " + this);
320             getLogger().debug("Use parameters is " + this._useParameters);
321             getLogger().debug("Use cookies is " + this._useCookies);
322             getLogger().debug("Use session info is " + this._useSessionInfo);
323             getLogger().debug("Check for included stylesheets is " + _checkIncludes);
324         }
325
326         // Get a Transformer Handler if we check for includes
327
// If we don't check the handler is get during setConsumer()
328
try {
329             if ( _checkIncludes ) {
330                 XSLTProcessor.TransformerHandlerAndValidity handlerAndValidity =
331                         this.xsltProcessor.getTransformerHandlerAndValidity(this.inputSource, null);
332                 this.transformerHandler = handlerAndValidity.getTransfomerHandler();
333                 this.transformerValidity = handlerAndValidity.getTransfomerValidity();
334             } else {
335                 this.transformerValidity = this.inputSource.getValidity();
336             }
337         } catch (XSLTProcessorException se) {
338             throw new ProcessingException("Unable to get transformer handler for " + this.inputSource.getURI(), se);
339         }
340     }
341
342     /**
343      * Generate the unique key.
344      * This key must be unique inside the space of this component.
345      *
346      * @return The generated key hashes the src
347      */

348     public Serializable JavaDoc getKey() {
349         Map JavaDoc map = getLogicSheetParameters();
350         if (map == null) {
351             return this.inputSource.getURI();
352         }
353
354         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
355         sb.append(this.inputSource.getURI());
356         Set JavaDoc entries = map.entrySet();
357         for(Iterator JavaDoc i=entries.iterator(); i.hasNext();){
358             sb.append(';');
359             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)i.next();
360             sb.append(entry.getKey());
361             sb.append('=');
362             sb.append(entry.getValue());
363         }
364         return sb.toString();
365     }
366
367     /**
368      * Generate the validity object.
369      *
370      * @return The generated validity object or <code>null</code> if the
371      * component is currently not cacheable.
372      */

373     public SourceValidity getValidity() {
374         //
375
// VG: Key is generated using parameter/value pairs,
376
// so this information does not need to be verified again
377
// (if parameter added/removed or value changed, key should
378
// change also), only stylesheet's validity is included.
379
//
380
return this.transformerValidity;
381     }
382
383     /**
384      * Set the <code>XMLConsumer</code> that will receive XML data.
385      */

386     public void setConsumer(XMLConsumer consumer) {
387
388         if ( this.transformerHandler == null ) {
389             try {
390                 this.transformerHandler = this.xsltProcessor.getTransformerHandler(this.inputSource);
391             } catch (XSLTProcessorException se) {
392                 // the exception will be thrown during startDocument()
393
this.exceptionDuringSetConsumer =
394                    new SAXException JavaDoc("Unable to get transformer handler for " + this.inputSource.getURI(), se);
395                 return;
396             }
397         }
398         final Map JavaDoc map = getLogicSheetParameters();
399         if (map != null) {
400             final javax.xml.transform.Transformer JavaDoc transformer = this.transformerHandler.getTransformer();
401             final Iterator JavaDoc iterator = map.entrySet().iterator();
402             while (iterator.hasNext()) {
403                 final Map.Entry JavaDoc entry = (Entry) iterator.next();
404                 transformer.setParameter((String JavaDoc)entry.getKey(), entry.getValue());
405             }
406         }
407
408         super.setContentHandler(this.transformerHandler);
409         super.setLexicalHandler(this.transformerHandler);
410
411         if (this.transformerHandler instanceof LogEnabled) {
412             ((LogEnabled)this.transformerHandler).enableLogging(getLogger());
413         }
414         // According to TrAX specs, all TransformerHandlers are LexicalHandlers
415
final SAXResult JavaDoc result = new SAXResult JavaDoc(consumer);
416         result.setLexicalHandler(consumer);
417         this.transformerHandler.setResult(result);
418
419         this.errorListener = new TraxErrorListener(getLogger(), this.inputSource.getURI());
420         this.transformerHandler.getTransformer().setErrorListener(this.errorListener);
421     }
422
423     /**
424      * Get the parameters for the logicsheet
425      */

426     protected Map JavaDoc getLogicSheetParameters() {
427         if (this.logicSheetParameters != null) {
428             return this.logicSheetParameters;
429         }
430         HashMap JavaDoc map = null;
431         if (par != null) {
432             String JavaDoc[] params = par.getNames();
433             if (params != null) {
434                 for(int i = 0; i < params.length; i++) {
435                     String JavaDoc name = params[i];
436                     if (isValidXSLTParameterName(name)) {
437                         String JavaDoc value = par.getParameter(name,null);
438                         if (value != null) {
439                             if (map == null) {
440                                 map = new HashMap JavaDoc(params.length);
441                             }
442                             map.put(name,value);
443                         }
444                     }
445                 }
446             }
447         }
448
449         if (this._useParameters) {
450             Request request = ObjectModelHelper.getRequest(objectModel);
451
452             Enumeration JavaDoc parameters = request.getParameterNames();
453             if (parameters != null) {
454                 while (parameters.hasMoreElements()) {
455                     String JavaDoc name = (String JavaDoc) parameters.nextElement();
456                     if (isValidXSLTParameterName(name)) {
457                         String JavaDoc value = request.getParameter(name);
458                         if (map == null) {
459                             map = new HashMap JavaDoc();
460                         }
461                         map.put(name,value);
462                     }
463                 }
464             }
465         }
466
467         if (this._useSessionInfo) {
468             final Request request = ObjectModelHelper.getRequest(objectModel);
469             if (map == null) {
470                 map = new HashMap JavaDoc(6);
471             }
472
473             final Session session = request.getSession(false);
474             if (session != null) {
475                 map.put("session-available", "true");
476                 map.put("session-is-new", BooleanUtils.toStringTrueFalse(session.isNew()));
477                 map.put("session-id-from-cookie", BooleanUtils.toStringTrueFalse(request.isRequestedSessionIdFromCookie()));
478                 map.put("session-id-from-url", BooleanUtils.toStringTrueFalse(request.isRequestedSessionIdFromURL()));
479                 map.put("session-valid", BooleanUtils.toStringTrueFalse(request.isRequestedSessionIdValid()));
480                 map.put("session-id", session.getId());
481             } else {
482                 map.put("session-available", "false");
483             }
484         }
485
486         if (this._useCookies) {
487             Request request = ObjectModelHelper.getRequest(objectModel);
488             Cookie cookies[] = request.getCookies();
489             if (cookies != null) {
490                 for (int i = 0; i < cookies.length; i++) {
491                     String JavaDoc name = cookies[i].getName();
492                     if (isValidXSLTParameterName(name)) {
493                         String JavaDoc value = cookies[i].getValue();
494                         if (map == null) {
495                             map = new HashMap JavaDoc(cookies.length);
496                         }
497                         map.put(name,value);
498                     }
499                 }
500             }
501         }
502         this.logicSheetParameters = map;
503         return this.logicSheetParameters;
504     }
505
506     /**
507      * Test if the name is a valid parameter name for XSLT
508      */

509     static boolean isValidXSLTParameterName(String JavaDoc name) {
510         if (name.length() == 0) {
511             return false;
512         }
513
514         char c = name.charAt(0);
515         if (!(Character.isLetter(c) || c == '_')) {
516             return false;
517         }
518
519         for (int i = name.length()-1; i > 1; i--) {
520             c = name.charAt(i);
521             if (!(Character.isLetterOrDigit(c) ||
522                     c == '-' ||
523                     c == '_' ||
524                     c == '.')) {
525                 return false;
526             }
527         }
528         return true;
529     }
530
531     /**
532      * Disposable
533      */

534     public void dispose() {
535         if ( this.manager != null ) {
536             this.manager.release(this.xsltProcessor);
537             this.xsltProcessor = null;
538             this.manager = null;
539         }
540     }
541
542     /**
543      * Recyclable
544      */

545     public void recycle() {
546         this.objectModel = null;
547         if (this.inputSource != null) {
548             this.resolver.release(this.inputSource);
549             this.inputSource = null;
550         }
551         this.resolver = null;
552         this.par = null;
553         if (!this.finishedDocument && transformerHandler != null) {
554             // This situation will only occur if an exception occured during pipeline execution.
555
// If Xalan is used in incremental mode, it is important that endDocument is called, otherwise
556
// the thread on which it runs the transformation will keep waiting.
557
// However, calling endDocument will cause the pipeline to continue executing, and thus the
558
// serializer will write output to the outputstream after what's already there (the error page),
559
// see also bug 13186.
560
if (xalanDtmManagerGetIncrementalMethod != null
561                 && transformerHandler.getClass().getName().equals("org.apache.xalan.transformer.TransformerHandlerImpl")) {
562                 try {
563                     final boolean incremental = ((Boolean JavaDoc)xalanDtmManagerGetIncrementalMethod.invoke(null, null)).booleanValue();
564                     if (incremental) {
565                         super.endDocument();
566                     }
567                 } catch (Exception JavaDoc ignore) {}
568             }
569         }
570         this.finishedDocument = true;
571         this.logicSheetParameters = null;
572         this.transformerHandler = null;
573         this.transformerValidity = null;
574         this.exceptionDuringSetConsumer = null;
575         this.errorListener = null;
576         super.recycle();
577     }
578
579     /**
580      * Fix for stopping hanging threads of Xalan
581      */

582     public void endDocument()
583     throws SAXException JavaDoc {
584         try {
585             super.endDocument();
586         } catch(Exception JavaDoc e) {
587             
588             Throwable JavaDoc realEx = this.errorListener.getThrowable();
589             if (realEx == null) realEx = e;
590             
591             if (realEx instanceof RuntimeException JavaDoc) {
592                 throw (RuntimeException JavaDoc)realEx;
593             }
594             
595             if (realEx instanceof SAXException JavaDoc) {
596                 throw (SAXException JavaDoc)realEx;
597             }
598             
599             if (realEx instanceof Error JavaDoc) {
600                 throw (Error JavaDoc)realEx;
601             }
602             
603             throw new NestableRuntimeException(realEx);
604         }
605         this.finishedDocument = true;
606     }
607
608     /* (non-Javadoc)
609      * @see org.xml.sax.ContentHandler#startDocument()
610      */

611     public void startDocument() throws SAXException JavaDoc {
612         // did an exception occur during setConsumer?
613
// if so, throw it here
614
if ( this.exceptionDuringSetConsumer != null ) {
615             throw this.exceptionDuringSetConsumer;
616         }
617         this.finishedDocument = false;
618         super.startDocument();
619     }
620 }
621
Popular Tags