code: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements. See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership. The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the  "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  /*
   * $Id$
   */
  
  package org.apache.xalan.xsltc.trax;
  
  import javax.xml.transform.Result;
  import javax.xml.transform.Transformer;
  import javax.xml.transform.TransformerException;
  import javax.xml.transform.sax.TransformerHandler;
  import javax.xml.transform.dom.DOMResult;
  
  import org.apache.xalan.xsltc.StripFilter;
  import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
  import org.apache.xalan.xsltc.dom.DOMWSFilter;
  import org.apache.xalan.xsltc.dom.SAXImpl;
  import org.apache.xalan.xsltc.dom.XSLTCDTMManager;
  import org.apache.xalan.xsltc.runtime.AbstractTranslet;
  import org.apache.xml.dtm.DTMWSFilter;
  import org.apache.xml.serializer.SerializationHandler;
  
  import org.xml.sax.Attributes;
  import org.xml.sax.ContentHandler;
  import org.xml.sax.DTDHandler;
  import org.xml.sax.Locator;
  import org.xml.sax.SAXException;
  import org.xml.sax.ext.DeclHandler;
  import org.xml.sax.ext.LexicalHandler;
  import org.xml.sax.helpers.DefaultHandler;
  
  /**
   * Implementation of a JAXP1.1 TransformerHandler
   * @author Morten Jorgensen
   */
  public class TransformerHandlerImpl implements TransformerHandler, DeclHandler {
  
      private TransformerImpl  _transformer;
      private AbstractTranslet _translet = null;
      private String           _systemId;
      private SAXImpl          _dom = null;
      private ContentHandler   _handler = null;
      private LexicalHandler   _lexHandler = null;
      private DTDHandler       _dtdHandler = null;
      private DeclHandler      _declHandler = null;
      private Result           _result = null;
      private Locator          _locator = null;
  
      private boolean          _done = false; // Set in endDocument()
  
      /**
       * A flag indicating whether this transformer handler implements the 
       * identity transform.
       */
      private boolean _isIdentity = false;
  
      /**
       * Cosntructor - pass in reference to a TransformerImpl object
       */
      public TransformerHandlerImpl(TransformerImpl transformer) {
  	// Save the reference to the transformer
  	_transformer = transformer;
  
  	if (transformer.isIdentity()) {
  	    // Set initial handler to the empty handler
  	    _handler = new DefaultHandler();
  	    _isIdentity = true;
  	}
  	else {
  	    // Get a reference to the translet wrapped inside the transformer
  	    _translet = _transformer.getTranslet();
  	}
      }
  
      /**
       * Implements javax.xml.transform.sax.TransformerHandler.getSystemId()
       * Get the base ID (URI or system ID) from where relative URLs will be
       * resolved.
       * @return The systemID that was set with setSystemId(String id)
       */
      public String getSystemId() {
  	return _systemId;
      }
  
      /**
       * Implements javax.xml.transform.sax.TransformerHandler.setSystemId()
       * Get the base ID (URI or system ID) from where relative URLs will be
       * resolved.
       * @param id Base URI for this stylesheet
       */
      public void setSystemId(String id) {
  	_systemId = id;
      }
  
      /**
       * Implements javax.xml.transform.sax.TransformerHandler.getTransformer()
       * Get the Transformer associated with this handler, which is needed in
       * order to set parameters and output properties.
       * @return The Transformer object
       */
      public Transformer getTransformer() {
  	return _transformer;
      }
  
      /**
       * Implements javax.xml.transform.sax.TransformerHandler.setResult()
       * Enables the user of the TransformerHandler to set the to set the Result
       * for the transformation.
       * @param result A Result instance, should not be null
       * @throws IllegalArgumentException if result is invalid for some reason
       */
      public void setResult(Result result) throws IllegalArgumentException {
  	_result = result;
  
      if (null == result) {
         ErrorMsg err = new ErrorMsg(ErrorMsg.ER_RESULT_NULL);
         throw new IllegalArgumentException(err.toString()); //"result should not be null");
      }    
         
  	if (_isIdentity) {
  	    try {
  		// Connect this object with output system directly
  		SerializationHandler outputHandler =
  		    _transformer.getOutputHandler(result);
  		_transformer.transferOutputProperties(outputHandler);
  
  		_handler = outputHandler;
  		_lexHandler = outputHandler;
  	    }
  	    catch (TransformerException e) {
  		_result = null;
  	    }
  	}
  	else if (_done) {
  	    // Run the transformation now, if not already done
  	    try {
  		_transformer.setDOM(_dom);
  		_transformer.transform(null, _result);
  	    }
  	    catch (TransformerException e) {
  		// What the hell are we supposed to do with this???
  		throw new IllegalArgumentException(e.getMessage());
  	    }
  	}
      }
  
      /**
       * Implements org.xml.sax.ContentHandler.characters()
       * Receive notification of character data.
       */
      public void characters(char[] ch, int start, int length) 
  	throws SAXException 
      {
  	_handler.characters(ch, start, length);
      }
  
      /**
       * Implements org.xml.sax.ContentHandler.startDocument()
       * Receive notification of the beginning of a document.
       */
      public void startDocument() throws SAXException {
  	// Make sure setResult() was called before the first SAX event
  	if (_result == null) {
  	    ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_SET_RESULT_ERR);
  	    throw new SAXException(err.toString());
  	}
  
          if (!_isIdentity) {
              boolean hasIdCall = (_translet != null) ? _translet.hasIdCall() : false;
              XSLTCDTMManager dtmManager = null;
              
              // Create an internal DOM (not W3C) and get SAX2 input handler
              try {
                  dtmManager = 
                      (XSLTCDTMManager)_transformer.getTransformerFactory()
                                                   .getDTMManagerClass()
                                                   .newInstance();
              } catch (Exception e) {
                  throw new SAXException(e);
              }
  
              DTMWSFilter wsFilter;
              if (_translet != null && _translet instanceof StripFilter) {
                  wsFilter = new DOMWSFilter(_translet);
              } else {
                  wsFilter = null;
              }            
            
              // Construct the DTM using the SAX events that come through
              _dom = (SAXImpl)dtmManager.getDTM(null, false, wsFilter, true,
                                                false, hasIdCall);         
  
              _handler = _dom.getBuilder();
              _lexHandler = (LexicalHandler) _handler;
              _dtdHandler = (DTDHandler) _handler;
              _declHandler = (DeclHandler) _handler;  
              
              
              // Set document URI
              _dom.setDocumentURI(_systemId);
              
              if (_locator != null) {
                  _handler.setDocumentLocator(_locator);
              }            
          }
  
  	// Proxy call
  	_handler.startDocument();
      }
  
      /**
       * Implements org.xml.sax.ContentHandler.endDocument()
       * Receive notification of the end of a document.
       */
      public void endDocument() throws SAXException {
  	// Signal to the DOMBuilder that the document is complete
  	_handler.endDocument();
  
  	if (!_isIdentity) {
  	    // Run the transformation now if we have a reference to a Result object
  	    if (_result != null) {
  		try {
  		    _transformer.setDOM(_dom);
  		    _transformer.transform(null, _result);
  		}
  		catch (TransformerException e) {
  		    throw new SAXException(e);
  		}
  	    }
  	    // Signal that the internal DOM is built (see 'setResult()').
  	    _done = true;
  
  	    // Set this DOM as the transformer's DOM
  	    _transformer.setDOM(_dom);
  	}
  	if (_isIdentity && _result instanceof DOMResult) {
  	    ((DOMResult)_result).setNode(_transformer.getTransletOutputHandlerFactory().getNode());
          }
      }
  	
      /**
       * Implements org.xml.sax.ContentHandler.startElement()
       * Receive notification of the beginning of an element.
       */
      public void startElement(String uri, String localName,
  			     String qname, Attributes attributes)
  	throws SAXException 
      {
  	_handler.startElement(uri, localName, qname, attributes);
      }
  	
      /**
       * Implements org.xml.sax.ContentHandler.endElement()
       * Receive notification of the end of an element.
       */
      public void endElement(String namespaceURI, String localName, String qname)
  	throws SAXException 
      {
  	_handler.endElement(namespaceURI, localName, qname);
      }
  
      /**
       * Implements org.xml.sax.ContentHandler.processingInstruction()
       * Receive notification of a processing instruction.
       */
      public void processingInstruction(String target, String data)
  	throws SAXException 
      {
  	_handler.processingInstruction(target, data);
      }
  
      /**
       * Implements org.xml.sax.ext.LexicalHandler.startCDATA()
       */
      public void startCDATA() throws SAXException { 
  	if (_lexHandler != null) {
  	    _lexHandler.startCDATA();
  	}
      }
  
      /**
       * Implements org.xml.sax.ext.LexicalHandler.endCDATA()
       */
      public void endCDATA() throws SAXException { 
  	if (_lexHandler != null) {
  	    _lexHandler.endCDATA();
  	}
      }
  
      /**
       * Implements org.xml.sax.ext.LexicalHandler.comment()
       * Receieve notification of a comment
       */
      public void comment(char[] ch, int start, int length) 
  	throws SAXException 
      { 
  	if (_lexHandler != null) {
  	    _lexHandler.comment(ch, start, length);
  	}
      }
  
      /**
       * Implements org.xml.sax.ContentHandler.ignorableWhitespace()
       * Receive notification of ignorable whitespace in element
       * content. Similar to characters(char[], int, int).
       */
      public void ignorableWhitespace(char[] ch, int start, int length)
  	throws SAXException 
      {
  	_handler.ignorableWhitespace(ch, start, length);
      }
  
      /**
       * Implements org.xml.sax.ContentHandler.setDocumentLocator()
       * Receive an object for locating the origin of SAX document events. 
       */
      public void setDocumentLocator(Locator locator) {
          _locator = locator;
  
          if (_handler != null) {
              _handler.setDocumentLocator(locator);
          }
      }
  
      /**
       * Implements org.xml.sax.ContentHandler.skippedEntity()
       * Receive notification of a skipped entity.
       */
      public void skippedEntity(String name) throws SAXException {
  	_handler.skippedEntity(name);
      }
  
      /**
       * Implements org.xml.sax.ContentHandler.startPrefixMapping()
       * Begin the scope of a prefix-URI Namespace mapping.
       */
      public void startPrefixMapping(String prefix, String uri) 
  	throws SAXException {
  	_handler.startPrefixMapping(prefix, uri);
      }
  
      /**
       * Implements org.xml.sax.ContentHandler.endPrefixMapping()
       * End the scope of a prefix-URI Namespace mapping.
       */
      public void endPrefixMapping(String prefix) throws SAXException {
  	_handler.endPrefixMapping(prefix);
      }
  
      /**
       * Implements org.xml.sax.ext.LexicalHandler.startDTD()
       */
      public void startDTD(String name, String publicId, String systemId) 
  	throws SAXException
      { 
  	if (_lexHandler != null) {
  	    _lexHandler.startDTD(name, publicId, systemId);
  	}
      }
  
      /**
       * Implements org.xml.sax.ext.LexicalHandler.endDTD()
       */
      public void endDTD() throws SAXException {
  	if (_lexHandler != null) {
  	    _lexHandler.endDTD();
  	}
      }
  
      /**
       * Implements org.xml.sax.ext.LexicalHandler.startEntity()
       */
      public void startEntity(String name) throws SAXException { 
  	if (_lexHandler != null) {
  	    _lexHandler.startEntity(name);
  	}
      }
  
      /**
       * Implements org.xml.sax.ext.LexicalHandler.endEntity()
       */
      public void endEntity(String name) throws SAXException { 
  	if (_lexHandler != null) {
  	    _lexHandler.endEntity(name);
  	}
      }
  
      /**
       * Implements org.xml.sax.DTDHandler.unparsedEntityDecl()
       */
      public void unparsedEntityDecl(String name, String publicId, 
  	String systemId, String notationName) throws SAXException 
      {
          if (_dtdHandler != null) {
  	    _dtdHandler.unparsedEntityDecl(name, publicId, systemId,
                                             notationName);
          }
      }
  
      /**
       * Implements org.xml.sax.DTDHandler.notationDecl()
       */
      public void notationDecl(String name, String publicId, String systemId) 
  	throws SAXException
      {
          if (_dtdHandler != null) {
  	    _dtdHandler.notationDecl(name, publicId, systemId);
          }
      }
  
      /**
       * Implements org.xml.sax.ext.DeclHandler.attributeDecl()
       */
      public void attributeDecl(String eName, String aName, String type, 
  	String valueDefault, String value) throws SAXException 
      {
          if (_declHandler != null) {
  	    _declHandler.attributeDecl(eName, aName, type, valueDefault, value);
          }
      }
  
      /**
       * Implements org.xml.sax.ext.DeclHandler.elementDecl()
       */
      public void elementDecl(String name, String model) 
  	throws SAXException
      {
          if (_declHandler != null) {
  	    _declHandler.elementDecl(name, model);
          }
      }
  
      /**
       * Implements org.xml.sax.ext.DeclHandler.externalEntityDecl()
       */
      public void externalEntityDecl(String name, String publicId, String systemId) 
  	throws SAXException
      {
          if (_declHandler != null) {
  	    _declHandler.externalEntityDecl(name, publicId, systemId);
          }
      }
  
      /**
       * Implements org.xml.sax.ext.DeclHandler.externalEntityDecl()
       */
      public void internalEntityDecl(String name, String value) 
  	throws SAXException
      {
          if (_declHandler != null) {
  	    _declHandler.internalEntityDecl(name, value);
          }
      }
  }
  