1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: TransformerHandlerImpl.java 468645 2006-10-28 06:57:24Z minchau $
20 */
21package org.apache.xalan.transformer;
22
23import java.io.IOException;
24
25import javax.xml.transform.Result;
26import javax.xml.transform.Transformer;
27import javax.xml.transform.sax.TransformerHandler;
28
29import org.apache.xalan.res.XSLMessages;
30import org.apache.xalan.res.XSLTErrorResources;
31import org.apache.xml.dtm.DTM;
32import org.apache.xml.dtm.DTMManager;
33import org.apache.xml.dtm.ref.IncrementalSAXSource_Filter;
34import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM;
35import org.apache.xpath.XPathContext;
36
37import org.xml.sax.Attributes;
38import org.xml.sax.ContentHandler;
39import org.xml.sax.DTDHandler;
40import org.xml.sax.EntityResolver;
41import org.xml.sax.ErrorHandler;
42import org.xml.sax.InputSource;
43import org.xml.sax.Locator;
44import org.xml.sax.SAXException;
45import org.xml.sax.SAXParseException;
46import org.xml.sax.ext.DeclHandler;
47import org.xml.sax.ext.LexicalHandler;
48import org.apache.xml.serializer.SerializationHandler;
49
50
51/**
52 * A TransformerHandler
53 * listens for SAX ContentHandler parse events and transforms
54 * them to a Result.
55 */
56public class TransformerHandlerImpl
57        implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler,
58                   LexicalHandler, TransformerHandler, DeclHandler
59{
60    /**
61     * The flag for the setting of the optimize feature;
62     */
63    private final boolean m_optimizer;
64
65    /**
66     * The flag for the setting of the incremental feature;
67     */
68    private final boolean m_incremental;
69
70    /**
71     * The flag for the setting of the source_location feature;
72     */
73    private final boolean m_source_location;
74
75  private boolean m_insideParse = false;
76
77  ////////////////////////////////////////////////////////////////////
78  // Constructors.
79  ////////////////////////////////////////////////////////////////////
80
81  /**
82   * Construct a TransformerHandlerImpl.
83   *
84   * @param transformer Non-null reference to the Xalan transformer impl.
85   * @param doFragment True if the result should be a document fragement.
86   * @param baseSystemID  The system ID to use as the base for relative URLs.
87   */
88  public TransformerHandlerImpl(TransformerImpl transformer,
89                                boolean doFragment, String baseSystemID)
90  {
91
92    super();
93
94    m_transformer = transformer;
95    m_baseSystemID = baseSystemID;
96
97    XPathContext xctxt = transformer.getXPathContext();
98    DTM dtm = xctxt.getDTM(null, true, transformer, true, true);
99
100    m_dtm = dtm;
101    dtm.setDocumentBaseURI(baseSystemID);
102
103    m_contentHandler = dtm.getContentHandler();
104    m_dtdHandler = dtm.getDTDHandler();
105    m_entityResolver = dtm.getEntityResolver();
106    m_errorHandler = dtm.getErrorHandler();
107    m_lexicalHandler = dtm.getLexicalHandler();
108    m_incremental = transformer.getIncremental();
109    m_optimizer = transformer.getOptimize();
110    m_source_location = transformer.getSource_location();
111  }
112
113  /**
114   * Do what needs to be done to shut down the CoRoutine management.
115   */
116  protected void clearCoRoutine()
117  {
118    clearCoRoutine(null);
119  }
120
121  /**
122   * Do what needs to be done to shut down the CoRoutine management.
123   */
124  protected void clearCoRoutine(SAXException ex)
125  {
126    if(null != ex)
127      m_transformer.setExceptionThrown(ex);
128
129    if(m_dtm instanceof SAX2DTM)
130    {
131      if(DEBUG)
132        System.err.println("In clearCoRoutine...");
133      try
134      {
135        SAX2DTM sax2dtm = ((SAX2DTM)m_dtm);
136        if(null != m_contentHandler
137           && m_contentHandler instanceof IncrementalSAXSource_Filter)
138        {
139          IncrementalSAXSource_Filter sp =
140            (IncrementalSAXSource_Filter)m_contentHandler;
141          // This should now be all that's needed.
142          sp.deliverMoreNodes(false);
143        }
144
145        sax2dtm.clearCoRoutine(true);
146        m_contentHandler = null;
147        m_dtdHandler = null;
148        m_entityResolver = null;
149        m_errorHandler = null;
150        m_lexicalHandler = null;
151      }
152      catch(Throwable throwable)
153      {
154        throwable.printStackTrace();
155      }
156
157      if(DEBUG)
158        System.err.println("...exiting clearCoRoutine");
159    }
160  }
161
162  ////////////////////////////////////////////////////////////////////
163  // Implementation of javax.xml.transform.sax.TransformerHandler.
164  ////////////////////////////////////////////////////////////////////
165
166  /**
167   * Enables the user of the TransformerHandler to set the
168   * to set the Result for the transformation.
169   *
170   * @param result A Result instance, should not be null.
171   *
172   * @throws IllegalArgumentException if result is invalid for some reason.
173   */
174  public void setResult(Result result) throws IllegalArgumentException
175  {
176
177    if (null == result)
178      throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_RESULT_NULL, null)); //"result should not be null");
179
180    try
181    {
182//      ContentHandler handler =
183//        m_transformer.createResultContentHandler(result);
184//      m_transformer.setContentHandler(handler);
185        SerializationHandler xoh =
186            m_transformer.createSerializationHandler(result);
187        m_transformer.setSerializationHandler(xoh);
188    }
189    catch (javax.xml.transform.TransformerException te)
190    {
191      throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_RESULT_COULD_NOT_BE_SET, null)); //"result could not be set");
192    }
193
194    m_result = result;
195  }
196
197  /**
198   * Set the base ID (URI or system ID) from where relative
199   * URLs will be resolved.
200   * @param systemID Base URI for the source tree.
201   */
202  public void setSystemId(String systemID)
203  {
204    m_baseSystemID = systemID;
205    m_dtm.setDocumentBaseURI(systemID);
206  }
207
208  /**
209   * Get the base ID (URI or system ID) from where relative
210   * URLs will be resolved.
211   * @return The systemID that was set with {@link #setSystemId}.
212   */
213  public String getSystemId()
214  {
215    return m_baseSystemID;
216  }
217
218  /**
219   * Get the Transformer associated with this handler, which
220   * is needed in order to set parameters and output properties.
221   *
222   * @return The Transformer associated with this handler
223   */
224  public Transformer getTransformer()
225  {
226    return m_transformer;
227  }
228
229  ////////////////////////////////////////////////////////////////////
230  // Implementation of org.xml.sax.EntityResolver.
231  ////////////////////////////////////////////////////////////////////
232
233  /**
234   * Filter an external entity resolution.
235   *
236   * @param publicId The entity's public identifier, or null.
237   * @param systemId The entity's system identifier.
238   * @return A new InputSource or null for the default.
239   *
240   * @throws IOException
241   * @throws SAXException The client may throw
242   *            an exception during processing.
243   * @throws java.io.IOException The client may throw an
244   *            I/O-related exception while obtaining the
245   *            new InputSource.
246   * @see org.xml.sax.EntityResolver#resolveEntity
247   */
248  public InputSource resolveEntity(String publicId, String systemId)
249          throws SAXException, IOException
250  {
251
252    if (m_entityResolver != null)
253    {
254      return m_entityResolver.resolveEntity(publicId, systemId);
255    }
256    else
257    {
258      return null;
259    }
260  }
261
262  ////////////////////////////////////////////////////////////////////
263  // Implementation of org.xml.sax.DTDHandler.
264  ////////////////////////////////////////////////////////////////////
265
266  /**
267   * Filter a notation declaration event.
268   *
269   * @param name The notation name.
270   * @param publicId The notation's public identifier, or null.
271   * @param systemId The notation's system identifier, or null.
272   * @throws SAXException The client may throw
273   *            an exception during processing.
274   * @see org.xml.sax.DTDHandler#notationDecl
275   */
276  public void notationDecl(String name, String publicId, String systemId)
277          throws SAXException
278  {
279
280    if (m_dtdHandler != null)
281    {
282      m_dtdHandler.notationDecl(name, publicId, systemId);
283    }
284  }
285
286  /**
287   * Filter an unparsed entity declaration event.
288   *
289   * @param name The entity name.
290   * @param publicId The entity's public identifier, or null.
291   * @param systemId The entity's system identifier, or null.
292   * @param notationName The name of the associated notation.
293   * @throws SAXException The client may throw
294   *            an exception during processing.
295   * @see org.xml.sax.DTDHandler#unparsedEntityDecl
296   */
297  public void unparsedEntityDecl(
298          String name, String publicId, String systemId, String notationName)
299            throws SAXException
300  {
301
302    if (m_dtdHandler != null)
303    {
304      m_dtdHandler.unparsedEntityDecl(name, publicId, systemId, notationName);
305    }
306  }
307
308  ////////////////////////////////////////////////////////////////////
309  // Implementation of org.xml.sax.ContentHandler.
310  ////////////////////////////////////////////////////////////////////
311
312  /**
313   * Filter a new document locator event.
314   *
315   * @param locator The document locator.
316   * @see org.xml.sax.ContentHandler#setDocumentLocator
317   */
318  public void setDocumentLocator(Locator locator)
319  {
320
321    if (DEBUG)
322      System.out.println("TransformerHandlerImpl#setDocumentLocator: "
323                         + locator.getSystemId());
324
325    this.m_locator = locator;
326
327    if(null == m_baseSystemID)
328    {
329      setSystemId(locator.getSystemId());
330    }
331
332    if (m_contentHandler != null)
333    {
334      m_contentHandler.setDocumentLocator(locator);
335    }
336  }
337
338  /**
339   * Filter a start document event.
340   *
341   * @throws SAXException The client may throw
342   *            an exception during processing.
343   * @see org.xml.sax.ContentHandler#startDocument
344   */
345  public void startDocument() throws SAXException
346  {
347
348    if (DEBUG)
349      System.out.println("TransformerHandlerImpl#startDocument");
350
351    m_insideParse = true;
352
353   // Thread listener = new Thread(m_transformer);
354
355    if (m_contentHandler != null)
356    {
357      //m_transformer.setTransformThread(listener);
358      if(m_incremental)
359      {
360        m_transformer.setSourceTreeDocForThread(m_dtm.getDocument());
361
362        int cpriority = Thread.currentThread().getPriority();
363
364        // runTransformThread is equivalent with the 2.0.1 code,
365        // except that the Thread may come from a pool.
366        m_transformer.runTransformThread( cpriority );
367      }
368
369      // This is now done _last_, because IncrementalSAXSource_Filter
370      // will immediately go into a "wait until events are requested"
371      // pause. I believe that will close our timing window.
372      // %REVIEW%
373      m_contentHandler.startDocument();
374   }
375
376   //listener.setDaemon(false);
377   //listener.start();
378
379  }
380
381  /**
382   * Filter an end document event.
383   *
384   * @throws SAXException The client may throw
385   *            an exception during processing.
386   * @see org.xml.sax.ContentHandler#endDocument
387   */
388  public void endDocument() throws SAXException
389  {
390
391    if (DEBUG)
392      System.out.println("TransformerHandlerImpl#endDocument");
393
394    m_insideParse = false;
395
396    if (m_contentHandler != null)
397    {
398      m_contentHandler.endDocument();
399    }
400
401    if(m_incremental)
402    {
403      m_transformer.waitTransformThread();
404    }
405    else
406    {
407      m_transformer.setSourceTreeDocForThread(m_dtm.getDocument());
408      m_transformer.run();
409    }
410   /* Thread transformThread = m_transformer.getTransformThread();
411
412    if (null != transformThread)
413    {
414      try
415      {
416
417        // This should wait until the transformThread is considered not alive.
418        transformThread.join();
419
420        if (!m_transformer.hasTransformThreadErrorCatcher())
421        {
422          Exception e = m_transformer.getExceptionThrown();
423
424          if (null != e)
425            throw new org.xml.sax.SAXException(e);
426        }
427
428        m_transformer.setTransformThread(null);
429      }
430      catch (InterruptedException ie){}
431    }*/
432  }
433
434  /**
435   * Filter a start Namespace prefix mapping event.
436   *
437   * @param prefix The Namespace prefix.
438   * @param uri The Namespace URI.
439   * @throws SAXException The client may throw
440   *            an exception during processing.
441   * @see org.xml.sax.ContentHandler#startPrefixMapping
442   */
443  public void startPrefixMapping(String prefix, String uri)
444          throws SAXException
445  {
446
447    if (DEBUG)
448      System.out.println("TransformerHandlerImpl#startPrefixMapping: "
449                         + prefix + ", " + uri);
450
451    if (m_contentHandler != null)
452    {
453      m_contentHandler.startPrefixMapping(prefix, uri);
454    }
455  }
456
457  /**
458   * Filter an end Namespace prefix mapping event.
459   *
460   * @param prefix The Namespace prefix.
461   * @throws SAXException The client may throw
462   *            an exception during processing.
463   * @see org.xml.sax.ContentHandler#endPrefixMapping
464   */
465  public void endPrefixMapping(String prefix) throws SAXException
466  {
467
468    if (DEBUG)
469      System.out.println("TransformerHandlerImpl#endPrefixMapping: "
470                         + prefix);
471
472    if (m_contentHandler != null)
473    {
474      m_contentHandler.endPrefixMapping(prefix);
475    }
476  }
477
478  /**
479   * Filter a start element event.
480   *
481   * @param uri The element's Namespace URI, or the empty string.
482   * @param localName The element's local name, or the empty string.
483   * @param qName The element's qualified (prefixed) name, or the empty
484   *        string.
485   * @param atts The element's attributes.
486   * @throws SAXException The client may throw
487   *            an exception during processing.
488   * @see org.xml.sax.ContentHandler#startElement
489   */
490  public void startElement(
491          String uri, String localName, String qName, Attributes atts)
492            throws SAXException
493  {
494
495    if (DEBUG)
496      System.out.println("TransformerHandlerImpl#startElement: " + qName);
497
498    if (m_contentHandler != null)
499    {
500      m_contentHandler.startElement(uri, localName, qName, atts);
501    }
502  }
503
504  /**
505   * Filter an end element event.
506   *
507   * @param uri The element's Namespace URI, or the empty string.
508   * @param localName The element's local name, or the empty string.
509   * @param qName The element's qualified (prefixed) name, or the empty
510   *        string.
511   * @throws SAXException The client may throw
512   *            an exception during processing.
513   * @see org.xml.sax.ContentHandler#endElement
514   */
515  public void endElement(String uri, String localName, String qName)
516          throws SAXException
517  {
518
519    if (DEBUG)
520      System.out.println("TransformerHandlerImpl#endElement: " + qName);
521
522    if (m_contentHandler != null)
523    {
524      m_contentHandler.endElement(uri, localName, qName);
525    }
526  }
527
528  /**
529   * Filter a character data event.
530   *
531   * @param ch An array of characters.
532   * @param start The starting position in the array.
533   * @param length The number of characters to use from the array.
534   * @throws SAXException The client may throw
535   *            an exception during processing.
536   * @see org.xml.sax.ContentHandler#characters
537   */
538  public void characters(char ch[], int start, int length) throws SAXException
539  {
540
541    if (DEBUG)
542      System.out.println("TransformerHandlerImpl#characters: " + start + ", "
543                         + length);
544
545    if (m_contentHandler != null)
546    {
547      m_contentHandler.characters(ch, start, length);
548    }
549  }
550
551  /**
552   * Filter an ignorable whitespace event.
553   *
554   * @param ch An array of characters.
555   * @param start The starting position in the array.
556   * @param length The number of characters to use from the array.
557   * @throws SAXException The client may throw
558   *            an exception during processing.
559   * @see org.xml.sax.ContentHandler#ignorableWhitespace
560   */
561  public void ignorableWhitespace(char ch[], int start, int length)
562          throws SAXException
563  {
564
565    if (DEBUG)
566      System.out.println("TransformerHandlerImpl#ignorableWhitespace: "
567                         + start + ", " + length);
568
569    if (m_contentHandler != null)
570    {
571      m_contentHandler.ignorableWhitespace(ch, start, length);
572    }
573  }
574
575  /**
576   * Filter a processing instruction event.
577   *
578   * @param target The processing instruction target.
579   * @param data The text following the target.
580   * @throws SAXException The client may throw
581   *            an exception during processing.
582   * @see org.xml.sax.ContentHandler#processingInstruction
583   */
584  public void processingInstruction(String target, String data)
585          throws SAXException
586  {
587
588    if (DEBUG)
589      System.out.println("TransformerHandlerImpl#processingInstruction: "
590                         + target + ", " + data);
591
592    if (m_contentHandler != null)
593    {
594      m_contentHandler.processingInstruction(target, data);
595    }
596  }
597
598  /**
599   * Filter a skipped entity event.
600   *
601   * @param name The name of the skipped entity.
602   * @throws SAXException The client may throw
603   *            an exception during processing.
604   * @see org.xml.sax.ContentHandler#skippedEntity
605   */
606  public void skippedEntity(String name) throws SAXException
607  {
608
609    if (DEBUG)
610      System.out.println("TransformerHandlerImpl#skippedEntity: " + name);
611
612    if (m_contentHandler != null)
613    {
614      m_contentHandler.skippedEntity(name);
615    }
616  }
617
618  ////////////////////////////////////////////////////////////////////
619  // Implementation of org.xml.sax.ErrorHandler.
620  ////////////////////////////////////////////////////////////////////
621
622  /**
623   * Filter a warning event.
624   *
625   * @param e The nwarning as an exception.
626   * @throws SAXException The client may throw
627   *            an exception during processing.
628   * @see org.xml.sax.ErrorHandler#warning
629   */
630  public void warning(SAXParseException e) throws SAXException
631  {
632    // This is not great, but we really would rather have the error
633    // handler be the error listener if it is a error handler.  Coroutine's fatalError
634    // can't really be configured, so I think this is the best thing right now
635    // for error reporting.  Possibly another JAXP 1.1 hole.  -sb
636    javax.xml.transform.ErrorListener errorListener = m_transformer.getErrorListener();
637    if(errorListener instanceof ErrorHandler)
638    {
639      ((ErrorHandler)errorListener).warning(e);
640    }
641    else
642    {
643      try
644      {
645        errorListener.warning(new javax.xml.transform.TransformerException(e));
646      }
647      catch(javax.xml.transform.TransformerException te)
648      {
649        throw e;
650      }
651    }
652  }
653
654  /**
655   * Filter an error event.
656   *
657   * @param e The error as an exception.
658   * @throws SAXException The client may throw
659   *            an exception during processing.
660   * @see org.xml.sax.ErrorHandler#error
661   */
662  public void error(SAXParseException e) throws SAXException
663  {
664    // %REVIEW% I don't think this should be called.  -sb
665    // clearCoRoutine(e);
666
667    // This is not great, but we really would rather have the error
668    // handler be the error listener if it is a error handler.  Coroutine's fatalError
669    // can't really be configured, so I think this is the best thing right now
670    // for error reporting.  Possibly another JAXP 1.1 hole.  -sb
671    javax.xml.transform.ErrorListener errorListener = m_transformer.getErrorListener();
672    if(errorListener instanceof ErrorHandler)
673    {
674      ((ErrorHandler)errorListener).error(e);
675      if(null != m_errorHandler)
676        m_errorHandler.error(e); // may not be called.
677    }
678    else
679    {
680      try
681      {
682        errorListener.error(new javax.xml.transform.TransformerException(e));
683        if(null != m_errorHandler)
684          m_errorHandler.error(e); // may not be called.
685      }
686      catch(javax.xml.transform.TransformerException te)
687      {
688        throw e;
689      }
690    }
691  }
692
693  /**
694   * Filter a fatal error event.
695   *
696   * @param e The error as an exception.
697   * @throws SAXException The client may throw
698   *            an exception during processing.
699   * @see org.xml.sax.ErrorHandler#fatalError
700   */
701  public void fatalError(SAXParseException e) throws SAXException
702  {
703    if(null != m_errorHandler)
704    {
705      try
706      {
707        m_errorHandler.fatalError(e);
708      }
709      catch(SAXParseException se)
710      {
711        // ignore
712      }
713      // clearCoRoutine(e);
714    }
715
716    // This is not great, but we really would rather have the error
717    // handler be the error listener if it is a error handler.  Coroutine's fatalError
718    // can't really be configured, so I think this is the best thing right now
719    // for error reporting.  Possibly another JAXP 1.1 hole.  -sb
720    javax.xml.transform.ErrorListener errorListener = m_transformer.getErrorListener();
721
722    if(errorListener instanceof ErrorHandler)
723    {
724      ((ErrorHandler)errorListener).fatalError(e);
725      if(null != m_errorHandler)
726        m_errorHandler.fatalError(e); // may not be called.
727    }
728    else
729    {
730      try
731      {
732        errorListener.fatalError(new javax.xml.transform.TransformerException(e));
733        if(null != m_errorHandler)
734          m_errorHandler.fatalError(e); // may not be called.
735      }
736      catch(javax.xml.transform.TransformerException te)
737      {
738        throw e;
739      }
740    }
741  }
742
743  ////////////////////////////////////////////////////////////////////
744  // Implementation of org.xml.sax.ext.LexicalHandler.
745  ////////////////////////////////////////////////////////////////////
746
747  /**
748   * Report the start of DTD declarations, if any.
749   *
750   * <p>Any declarations are assumed to be in the internal subset
751   * unless otherwise indicated by a {@link #startEntity startEntity}
752   * event.</p>
753   *
754   * <p>Note that the start/endDTD events will appear within
755   * the start/endDocument events from ContentHandler and
756   * before the first startElement event.</p>
757   *
758   * @param name The document type name.
759   * @param publicId The declared public identifier for the
760   *        external DTD subset, or null if none was declared.
761   * @param systemId The declared system identifier for the
762   *        external DTD subset, or null if none was declared.
763   * @throws SAXException The application may raise an
764   *            exception.
765   * @see #endDTD
766   * @see #startEntity
767   */
768  public void startDTD(String name, String publicId, String systemId)
769          throws SAXException
770  {
771
772    if (DEBUG)
773      System.out.println("TransformerHandlerImpl#startDTD: " + name + ", "
774                         + publicId + ", " + systemId);
775
776    if (null != m_lexicalHandler)
777    {
778      m_lexicalHandler.startDTD(name, publicId, systemId);
779    }
780  }
781
782  /**
783   * Report the end of DTD declarations.
784   *
785   * @throws SAXException The application may raise an exception.
786   * @see #startDTD
787   */
788  public void endDTD() throws SAXException
789  {
790
791    if (DEBUG)
792      System.out.println("TransformerHandlerImpl#endDTD");
793
794    if (null != m_lexicalHandler)
795    {
796      m_lexicalHandler.endDTD();
797    }
798  }
799
800  /**
801   * Report the beginning of an entity in content.
802   *
803   * <p><strong>NOTE:</entity> entity references in attribute
804   * values -- and the start and end of the document entity --
805   * are never reported.</p>
806   *
807   * <p>The start and end of the external DTD subset are reported
808   * using the pseudo-name "[dtd]".  All other events must be
809   * properly nested within start/end entity events.</p>
810   *
811   * <p>Note that skipped entities will be reported through the
812   * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity}
813   * event, which is part of the ContentHandler interface.</p>
814   *
815   * @param name The name of the entity.  If it is a parameter
816   *        entity, the name will begin with '%'.
817   * @throws SAXException The application may raise an exception.
818   * @see #endEntity
819   * @see org.xml.sax.ext.DeclHandler#internalEntityDecl
820   * @see org.xml.sax.ext.DeclHandler#externalEntityDecl
821   */
822  public void startEntity(String name) throws SAXException
823  {
824
825    if (DEBUG)
826      System.out.println("TransformerHandlerImpl#startEntity: " + name);
827
828    if (null != m_lexicalHandler)
829    {
830      m_lexicalHandler.startEntity(name);
831    }
832  }
833
834  /**
835   * Report the end of an entity.
836   *
837   * @param name The name of the entity that is ending.
838   * @throws SAXException The application may raise an exception.
839   * @see #startEntity
840   */
841  public void endEntity(String name) throws SAXException
842  {
843
844    if (DEBUG)
845      System.out.println("TransformerHandlerImpl#endEntity: " + name);
846
847    if (null != m_lexicalHandler)
848    {
849      m_lexicalHandler.endEntity(name);
850    }
851  }
852
853  /**
854   * Report the start of a CDATA section.
855   *
856   * <p>The contents of the CDATA section will be reported through
857   * the regular {@link org.xml.sax.ContentHandler#characters
858   * characters} event.</p>
859   *
860   * @throws SAXException The application may raise an exception.
861   * @see #endCDATA
862   */
863  public void startCDATA() throws SAXException
864  {
865
866    if (DEBUG)
867      System.out.println("TransformerHandlerImpl#startCDATA");
868
869    if (null != m_lexicalHandler)
870    {
871      m_lexicalHandler.startCDATA();
872    }
873  }
874
875  /**
876   * Report the end of a CDATA section.
877   *
878   * @throws SAXException The application may raise an exception.
879   * @see #startCDATA
880   */
881  public void endCDATA() throws SAXException
882  {
883
884    if (DEBUG)
885      System.out.println("TransformerHandlerImpl#endCDATA");
886
887    if (null != m_lexicalHandler)
888    {
889      m_lexicalHandler.endCDATA();
890    }
891  }
892
893  /**
894   * Report an XML comment anywhere in the document.
895   *
896   * <p>This callback will be used for comments inside or outside the
897   * document element, including comments in the external DTD
898   * subset (if read).</p>
899   *
900   * @param ch An array holding the characters in the comment.
901   * @param start The starting position in the array.
902   * @param length The number of characters to use from the array.
903   * @throws SAXException The application may raise an exception.
904   */
905  public void comment(char ch[], int start, int length) throws SAXException
906  {
907
908    if (DEBUG)
909      System.out.println("TransformerHandlerImpl#comment: " + start + ", "
910                         + length);
911
912    if (null != m_lexicalHandler)
913    {
914      m_lexicalHandler.comment(ch, start, length);
915    }
916  }
917
918  ////////////////////////////////////////////////////////////////////
919  // Implementation of org.xml.sax.ext.DeclHandler.
920  ////////////////////////////////////////////////////////////////////
921
922  /**
923   * Report an element type declaration.
924   *
925   * <p>The content model will consist of the string "EMPTY", the
926   * string "ANY", or a parenthesised group, optionally followed
927   * by an occurrence indicator.  The model will be normalized so
928   * that all whitespace is removed,and will include the enclosing
929   * parentheses.</p>
930   *
931   * @param name The element type name.
932   * @param model The content model as a normalized string.
933   * @throws SAXException The application may raise an exception.
934   */
935  public void elementDecl(String name, String model) throws SAXException
936  {
937
938    if (DEBUG)
939      System.out.println("TransformerHandlerImpl#elementDecl: " + name + ", "
940                         + model);
941
942    if (null != m_declHandler)
943    {
944      m_declHandler.elementDecl(name, model);
945    }
946  }
947
948  /**
949   * Report an attribute type declaration.
950   *
951   * <p>Only the effective (first) declaration for an attribute will
952   * be reported.  The type will be one of the strings "CDATA",
953   * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY",
954   * "ENTITIES", or "NOTATION", or a parenthesized token group with
955   * the separator "|" and all whitespace removed.</p>
956   *
957   * @param eName The name of the associated element.
958   * @param aName The name of the attribute.
959   * @param type A string representing the attribute type.
960   * @param valueDefault A string representing the attribute default
961   *        ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if
962   *        none of these applies.
963   * @param value A string representing the attribute's default value,
964   *        or null if there is none.
965   * @throws SAXException The application may raise an exception.
966   */
967  public void attributeDecl(
968          String eName, String aName, String type, String valueDefault, String value)
969            throws SAXException
970  {
971
972    if (DEBUG)
973      System.out.println("TransformerHandlerImpl#attributeDecl: " + eName
974                         + ", " + aName + ", etc...");
975
976    if (null != m_declHandler)
977    {
978      m_declHandler.attributeDecl(eName, aName, type, valueDefault, value);
979    }
980  }
981
982  /**
983   * Report an internal entity declaration.
984   *
985   * <p>Only the effective (first) declaration for each entity
986   * will be reported.</p>
987   *
988   * @param name The name of the entity.  If it is a parameter
989   *        entity, the name will begin with '%'.
990   * @param value The replacement text of the entity.
991   * @throws SAXException The application may raise an exception.
992   * @see #externalEntityDecl
993   * @see org.xml.sax.DTDHandler#unparsedEntityDecl
994   */
995  public void internalEntityDecl(String name, String value)
996          throws SAXException
997  {
998
999    if (DEBUG)
1000      System.out.println("TransformerHandlerImpl#internalEntityDecl: " + name
1001                         + ", " + value);
1002
1003    if (null != m_declHandler)
1004    {
1005      m_declHandler.internalEntityDecl(name, value);
1006    }
1007  }
1008
1009  /**
1010   * Report a parsed external entity declaration.
1011   *
1012   * <p>Only the effective (first) declaration for each entity
1013   * will be reported.</p>
1014   *
1015   * @param name The name of the entity.  If it is a parameter
1016   *        entity, the name will begin with '%'.
1017   * @param publicId The declared public identifier of the entity, or
1018   *        null if none was declared.
1019   * @param systemId The declared system identifier of the entity.
1020   * @throws SAXException The application may raise an exception.
1021   * @see #internalEntityDecl
1022   * @see org.xml.sax.DTDHandler#unparsedEntityDecl
1023   */
1024  public void externalEntityDecl(
1025          String name, String publicId, String systemId) throws SAXException
1026  {
1027
1028    if (DEBUG)
1029      System.out.println("TransformerHandlerImpl#externalEntityDecl: " + name
1030                         + ", " + publicId + ", " + systemId);
1031
1032    if (null != m_declHandler)
1033    {
1034      m_declHandler.externalEntityDecl(name, publicId, systemId);
1035    }
1036  }
1037
1038  ////////////////////////////////////////////////////////////////////
1039  // Internal state.
1040  ////////////////////////////////////////////////////////////////////
1041
1042  /** Set to true for diagnostics output.         */
1043  private static boolean DEBUG = false;
1044
1045  /**
1046   * The transformer this will use to transform a
1047   * source tree into a result tree.
1048   */
1049  private TransformerImpl m_transformer;
1050
1051  /** The system ID to use as a base for relative URLs. */
1052  private String m_baseSystemID;
1053
1054  /** The result for the transformation. */
1055  private Result m_result = null;
1056
1057  /** The locator for this TransformerHandler. */
1058  private Locator m_locator = null;
1059
1060  /** The entity resolver to aggregate to. */
1061  private EntityResolver m_entityResolver = null;
1062
1063  /** The DTD handler to aggregate to. */
1064  private DTDHandler m_dtdHandler = null;
1065
1066  /** The content handler to aggregate to. */
1067  private ContentHandler m_contentHandler = null;
1068
1069  /** The error handler to aggregate to. */
1070  private ErrorHandler m_errorHandler = null;
1071
1072  /** The lexical handler to aggregate to. */
1073  private LexicalHandler m_lexicalHandler = null;
1074
1075  /** The decl handler to aggregate to. */
1076  private DeclHandler m_declHandler = null;
1077
1078  /** The Document Table Instance we are transforming. */
1079  DTM m_dtm;
1080}
1081