1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2001-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: TransformerImpl.java,v 1.10 2007/06/13 01:57:09 joehw Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.trax;
  25 
  26 import com.sun.org.apache.xalan.internal.XalanConstants;
  27 import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
  28 import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager;
  29 import java.io.File;
  30 import java.io.FileOutputStream;
  31 import java.io.IOException;
  32 import java.io.InputStream;
  33 import java.io.OutputStream;
  34 import java.io.Reader;
  35 import java.io.Writer;
  36 import java.net.URI;
  37 import java.net.URL;
  38 import java.net.URLConnection;
  39 import java.net.UnknownServiceException;
  40 import java.util.Enumeration;
  41 import java.util.Properties;
  42 import java.util.StringTokenizer;
  43 import java.util.Vector;
  44 import java.lang.reflect.Constructor;
  45 
  46 import javax.xml.parsers.DocumentBuilder;
  47 import javax.xml.parsers.DocumentBuilderFactory;
  48 import javax.xml.parsers.ParserConfigurationException;
  49 import javax.xml.stream.XMLEventReader;
  50 import javax.xml.stream.XMLStreamReader;
  51 import javax.xml.transform.ErrorListener;
  52 import javax.xml.transform.OutputKeys;
  53 import javax.xml.transform.Result;
  54 import javax.xml.transform.Source;
  55 import javax.xml.transform.Transformer;
  56 import javax.xml.transform.TransformerException;
  57 import javax.xml.transform.URIResolver;
  58 import javax.xml.transform.dom.DOMResult;
  59 import javax.xml.transform.dom.DOMSource;
  60 import javax.xml.transform.sax.SAXResult;
  61 import javax.xml.transform.sax.SAXSource;
  62 import javax.xml.transform.stax.StAXResult;
  63 import javax.xml.transform.stax.StAXSource;
  64 import javax.xml.transform.stream.StreamResult;
  65 import javax.xml.transform.stream.StreamSource;
  66 import javax.xml.XMLConstants;
  67 
  68 import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
  69 
  70 import com.sun.org.apache.xalan.internal.xsltc.DOM;
  71 import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
  72 import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
  73 import com.sun.org.apache.xalan.internal.xsltc.StripFilter;
  74 import com.sun.org.apache.xalan.internal.xsltc.Translet;
  75 import com.sun.org.apache.xalan.internal.xsltc.TransletException;
  76 import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory;
  77 import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
  78 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  79 import com.sun.org.apache.xalan.internal.xsltc.dom.DOMWSFilter;
  80 import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl;
  81 import com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager;
  82 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  83 import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
  84 import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
  85 
  86 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  87 import com.sun.org.apache.xml.internal.utils.XMLReaderManager;
  88 
  89 import org.xml.sax.ContentHandler;
  90 import org.xml.sax.InputSource;
  91 import org.xml.sax.SAXException;
  92 import org.xml.sax.XMLReader;
  93 import org.xml.sax.ext.LexicalHandler;
  94 
  95 /**
  96  * @author Morten Jorgensen
  97  * @author G. Todd Miller
  98  * @author Santiago Pericas-Geertsen
  99  */
 100 public final class TransformerImpl extends Transformer
 101     implements DOMCache, ErrorListener
 102 {
 103 
 104     private final static String LEXICAL_HANDLER_PROPERTY =
 105         "http://xml.org/sax/properties/lexical-handler";
 106     private static final String NAMESPACE_FEATURE =
 107         "http://xml.org/sax/features/namespaces";
 108 
 109     /**
 110      * Namespace prefixes feature for {@link XMLReader}.
 111      */
 112     private static final String NAMESPACE_PREFIXES_FEATURE =
 113         "http://xml.org/sax/features/namespace-prefixes";
 114 
 115     /**
 116      * A reference to the translet or null if the identity transform.
 117      */
 118     private AbstractTranslet _translet = null;
 119 
 120     /**
 121      * The output method of this transformation.
 122      */
 123     private String _method = null;
 124 
 125     /**
 126      * The output encoding of this transformation.
 127      */
 128     private String _encoding = null;
 129 
 130     /**
 131      * The systemId set in input source.
 132      */
 133     private String _sourceSystemId = null;
 134 
 135     /**
 136      * An error listener for runtime errors.
 137      */
 138     private ErrorListener _errorListener = this;
 139 
 140     /**
 141      * A reference to a URI resolver for calls to document().
 142      */
 143     private URIResolver _uriResolver = null;
 144 
 145     /**
 146      * Output properties of this transformer instance.
 147      */
 148     private Properties _properties, _propertiesClone;
 149 
 150     /**
 151      * A reference to an output handler factory.
 152      */
 153     private TransletOutputHandlerFactory _tohFactory = null;
 154 
 155     /**
 156      * A reference to a internal DOM representation of the input.
 157      */
 158     private DOM _dom = null;
 159 
 160     /**
 161      * Number of indent spaces to add when indentation is on.
 162      */
 163     private int _indentNumber;
 164 
 165     /**
 166      * A reference to the transformer factory that this templates
 167      * object belongs to.
 168      */
 169     private TransformerFactoryImpl _tfactory = null;
 170 
 171     /**
 172      * A reference to the output stream, if we create one in our code.
 173      */
 174     private OutputStream _ostream = null;
 175 
 176     /**
 177      * A reference to the XSLTCDTMManager which is used to build the DOM/DTM
 178      * for this transformer.
 179      */
 180     private XSLTCDTMManager _dtmManager = null;
 181 
 182     /**
 183      * A reference to an object that creates and caches XMLReader objects.
 184      */
 185     private XMLReaderManager _readerManager;
 186 
 187     /**
 188      * A flag indicating whether we use incremental building of the DTM.
 189      */
 190     //private boolean _isIncremental = false;
 191 
 192     /**
 193      * A flag indicating whether this transformer implements the identity
 194      * transform.
 195      */
 196     private boolean _isIdentity = false;
 197 
 198     /**
 199      * State of the secure processing feature.
 200      */
 201     private boolean _isSecureProcessing = false;
 202 
 203     /**
 204      * Indicates whether implementation parts should use
 205      *   service loader (or similar).
 206      * Note the default value (false) is the safe option..
 207      */
 208     private boolean _useServicesMechanism;
 209     /**
 210      * protocols allowed for external references set by the stylesheet processing instruction, Import and Include element.
 211      */
 212     private String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
 213      /**
 214      * protocols allowed for external DTD references in source file and/or stylesheet.
 215      */
 216     private String _accessExternalDTD = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
 217 
 218     private XMLSecurityManager _securityManager;
 219     /**
 220      * A hashtable to store parameters for the identity transform. These
 221      * are not needed during the transformation, but we must keep track of
 222      * them to be fully complaint with the JAXP API.
 223      */
 224     private Hashtable _parameters = null;
 225 
 226     /**
 227      * This class wraps an ErrorListener into a MessageHandler in order to
 228      * capture messages reported via xsl:message.
 229      */
 230     static class MessageHandler
 231            extends com.sun.org.apache.xalan.internal.xsltc.runtime.MessageHandler
 232     {
 233         private ErrorListener _errorListener;
 234 
 235         public MessageHandler(ErrorListener errorListener) {
 236             _errorListener = errorListener;
 237         }
 238 
 239         @Override
 240         public void displayMessage(String msg) {
 241             if(_errorListener == null) {
 242                 System.err.println(msg);
 243             }
 244             else {
 245                 try {
 246                     _errorListener.warning(new TransformerException(msg));
 247                 }
 248                 catch (TransformerException e) {
 249                     // ignored
 250                 }
 251             }
 252         }
 253     }
 254 
 255     protected TransformerImpl(Properties outputProperties, int indentNumber,
 256         TransformerFactoryImpl tfactory)
 257     {
 258         this(null, outputProperties, indentNumber, tfactory);
 259         _isIdentity = true;
 260         // _properties.put(OutputKeys.METHOD, "xml");
 261     }
 262 
 263     protected TransformerImpl(Translet translet, Properties outputProperties,
 264         int indentNumber, TransformerFactoryImpl tfactory)
 265     {
 266         _translet = (AbstractTranslet) translet;
 267         _properties = createOutputProperties(outputProperties);
 268         _propertiesClone = (Properties) _properties.clone();
 269         _indentNumber = indentNumber;
 270         _tfactory = tfactory;
 271         _useServicesMechanism = _tfactory.useServicesMechnism();
 272         _accessExternalStylesheet = (String)_tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
 273         _accessExternalDTD = (String)_tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_DTD);
 274         _securityManager = (XMLSecurityManager)_tfactory.getAttribute(XalanConstants.SECURITY_MANAGER);
 275         _readerManager = XMLReaderManager.getInstance(_useServicesMechanism);
 276         _readerManager.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, _accessExternalDTD);
 277         _readerManager.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, _isSecureProcessing);
 278         _readerManager.setProperty(XalanConstants.SECURITY_MANAGER, _securityManager);
 279         //_isIncremental = tfactory._incremental;
 280     }
 281 
 282     /**
 283      * Return the state of the secure processing feature.
 284      */
 285     public boolean isSecureProcessing() {
 286         return _isSecureProcessing;
 287     }
 288 
 289     /**
 290      * Set the state of the secure processing feature.
 291      */
 292     public void setSecureProcessing(boolean flag) {
 293         _isSecureProcessing = flag;
 294         _readerManager.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, _isSecureProcessing);
 295     }
 296     /**
 297      * Return the state of the services mechanism feature.
 298      */
 299     public boolean useServicesMechnism() {
 300         return _useServicesMechanism;
 301     }
 302 
 303     /**
 304      * Set the state of the services mechanism feature.
 305      */
 306     public void setServicesMechnism(boolean flag) {
 307         _useServicesMechanism = flag;
 308     }
 309 
 310     /**
 311      * Returns the translet wrapped inside this Transformer or
 312      * null if this is the identity transform.
 313      */
 314     protected AbstractTranslet getTranslet() {
 315         return _translet;
 316     }
 317 
 318     public boolean isIdentity() {
 319         return _isIdentity;
 320     }
 321 
 322     /**
 323      * Implements JAXP's Transformer.transform()
 324      *
 325      * @param source Contains the input XML document
 326      * @param result Will contain the output from the transformation
 327      * @throws TransformerException
 328      */
 329     @Override
 330     public void transform(Source source, Result result)
 331         throws TransformerException
 332     {
 333         if (!_isIdentity) {
 334             if (_translet == null) {
 335                 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_TRANSLET_ERR);
 336                 throw new TransformerException(err.toString());
 337             }
 338             // Pass output properties to the translet
 339             transferOutputProperties(_translet);
 340         }
 341 
 342         final SerializationHandler toHandler = getOutputHandler(result);
 343         if (toHandler == null) {
 344             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_HANDLER_ERR);
 345             throw new TransformerException(err.toString());
 346         }
 347 
 348         if (_uriResolver != null && !_isIdentity) {
 349             _translet.setDOMCache(this);
 350         }
 351 
 352         // Pass output properties to handler if identity
 353         if (_isIdentity) {
 354             transferOutputProperties(toHandler);
 355         }
 356 
 357         transform(source, toHandler, _encoding);
 358         try{
 359             if (result instanceof DOMResult) {
 360                 ((DOMResult)result).setNode(_tohFactory.getNode());
 361             } else if (result instanceof StAXResult) {
 362                   if (((StAXResult) result).getXMLEventWriter() != null)
 363                 {
 364                     (_tohFactory.getXMLEventWriter()).flush();
 365                 }
 366                 else if (((StAXResult) result).getXMLStreamWriter() != null) {
 367                     (_tohFactory.getXMLStreamWriter()).flush();
 368                     //result = new StAXResult(_tohFactory.getXMLStreamWriter());
 369                 }
 370             }
 371         } catch (Exception e) {
 372             System.out.println("Result writing error");
 373         }
 374     }
 375 
 376     /**
 377      * Create an output handler for the transformation output based on
 378      * the type and contents of the TrAX Result object passed to the
 379      * transform() method.
 380      */
 381     public SerializationHandler getOutputHandler(Result result)
 382         throws TransformerException
 383     {
 384         // Get output method using get() to ignore defaults
 385         _method = (String) _properties.get(OutputKeys.METHOD);
 386 
 387         // Get encoding using getProperty() to use defaults
 388         _encoding = (String) _properties.getProperty(OutputKeys.ENCODING);
 389 
 390         _tohFactory = TransletOutputHandlerFactory.newInstance(_useServicesMechanism);
 391         _tohFactory.setEncoding(_encoding);
 392         if (_method != null) {
 393             _tohFactory.setOutputMethod(_method);
 394         }
 395 
 396         // Set indentation number in the factory
 397         if (_indentNumber >= 0) {
 398             _tohFactory.setIndentNumber(_indentNumber);
 399         }
 400 
 401         // Return the content handler for this Result object
 402         try {
 403             // Result object could be SAXResult, DOMResult, or StreamResult
 404             if (result instanceof SAXResult) {
 405                 final SAXResult target = (SAXResult)result;
 406                 final ContentHandler handler = target.getHandler();
 407 
 408                 _tohFactory.setHandler(handler);
 409 
 410                 /**
 411                  * Fix for bug 24414
 412                  * If the lexicalHandler is set then we need to get that
 413                  * for obtaining the lexical information
 414                  */
 415                 LexicalHandler lexicalHandler = target.getLexicalHandler();
 416 
 417                 if (lexicalHandler != null ) {
 418                     _tohFactory.setLexicalHandler(lexicalHandler);
 419                 }
 420 
 421                 _tohFactory.setOutputType(TransletOutputHandlerFactory.SAX);
 422                 return _tohFactory.getSerializationHandler();
 423             }
 424             else if (result instanceof StAXResult) {
 425                 if (((StAXResult) result).getXMLEventWriter() != null)
 426                     _tohFactory.setXMLEventWriter(((StAXResult) result).getXMLEventWriter());
 427                 else if (((StAXResult) result).getXMLStreamWriter() != null)
 428                     _tohFactory.setXMLStreamWriter(((StAXResult) result).getXMLStreamWriter());
 429                 _tohFactory.setOutputType(TransletOutputHandlerFactory.STAX);
 430                 return _tohFactory.getSerializationHandler();
 431             }
 432             else if (result instanceof DOMResult) {
 433                 _tohFactory.setNode(((DOMResult) result).getNode());
 434                 _tohFactory.setNextSibling(((DOMResult) result).getNextSibling());
 435                 _tohFactory.setOutputType(TransletOutputHandlerFactory.DOM);
 436                 return _tohFactory.getSerializationHandler();
 437             }
 438             else if (result instanceof StreamResult) {
 439                 // Get StreamResult
 440                 final StreamResult target = (StreamResult) result;
 441 
 442                 // StreamResult may have been created with a java.io.File,
 443                 // java.io.Writer, java.io.OutputStream or just a String
 444                 // systemId.
 445 
 446                 _tohFactory.setOutputType(TransletOutputHandlerFactory.STREAM);
 447 
 448                 // try to get a Writer from Result object
 449                 final Writer writer = target.getWriter();
 450                 if (writer != null) {
 451                     _tohFactory.setWriter(writer);
 452                     return _tohFactory.getSerializationHandler();
 453                 }
 454 
 455                 // or try to get an OutputStream from Result object
 456                 final OutputStream ostream = target.getOutputStream();
 457                 if (ostream != null) {
 458                     _tohFactory.setOutputStream(ostream);
 459                     return _tohFactory.getSerializationHandler();
 460                 }
 461 
 462                 // or try to get just a systemId string from Result object
 463                 String systemId = result.getSystemId();
 464                 if (systemId == null) {
 465                     ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_RESULT_ERR);
 466                     throw new TransformerException(err.toString());
 467                 }
 468 
 469                 // System Id may be in one of several forms, (1) a uri
 470                 // that starts with 'file:', (2) uri that starts with 'http:'
 471                 // or (3) just a filename on the local system.
 472                 URL url;
 473                 if (systemId.startsWith("file:")) {
 474                     // if StreamResult(File) or setSystemID(File) was used,
 475                     // the systemId will be URI encoded as a result of File.toURI(),
 476                     // it must be decoded for use by URL
 477                     try{
 478                         URI uri = new URI(systemId) ;
 479                         systemId = "file:";
 480 
 481                         String host = uri.getHost(); // decoded String
 482                         String path = uri.getPath(); //decoded String
 483                         if (path == null) {
 484                          path = "";
 485                         }
 486 
 487                         // if host (URI authority) then file:// + host + path
 488                         // else just path (may be absolute or relative)
 489                         if (host != null) {
 490                          systemId += "//" + host + path;
 491                         } else {
 492                          systemId += "//" + path;
 493                         }
 494                     }
 495                     catch (Exception  exception) {
 496                         // URI exception which means nothing can be done so OK to ignore
 497                     }
 498 
 499                     url = new URL(systemId);
 500                     _ostream = new FileOutputStream(url.getFile());
 501                     _tohFactory.setOutputStream(_ostream);
 502                     return _tohFactory.getSerializationHandler();
 503                 }
 504                 else if (systemId.startsWith("http:")) {
 505                     url = new URL(systemId);
 506                     final URLConnection connection = url.openConnection();
 507                     _tohFactory.setOutputStream(_ostream = connection.getOutputStream());
 508                     return _tohFactory.getSerializationHandler();
 509                 }
 510                 else {
 511                     // system id is just a filename
 512                     _tohFactory.setOutputStream(
 513                         _ostream = new FileOutputStream(new File(systemId)));
 514                     return _tohFactory.getSerializationHandler();
 515                 }
 516             }
 517         }
 518         // If we cannot write to the location specified by the SystemId
 519         catch (UnknownServiceException e) {
 520             throw new TransformerException(e);
 521         }
 522         catch (ParserConfigurationException e) {
 523             throw new TransformerException(e);
 524         }
 525         // If we cannot create the file specified by the SystemId
 526         catch (IOException e) {
 527             throw new TransformerException(e);
 528         }
 529         return null;
 530     }
 531 
 532     /**
 533      * Set the internal DOM that will be used for the next transformation
 534      */
 535     protected void setDOM(DOM dom) {
 536         _dom = dom;
 537     }
 538 
 539     /**
 540      * Builds an internal DOM from a TrAX Source object
 541      */
 542     private DOM getDOM(Source source) throws TransformerException {
 543         try {
 544             DOM dom;
 545 
 546             if (source != null) {
 547                 DTMWSFilter wsfilter;
 548                 if (_translet != null && _translet instanceof StripFilter) {
 549                     wsfilter = new DOMWSFilter(_translet);
 550                  } else {
 551                     wsfilter = null;
 552                  }
 553 
 554                  boolean hasIdCall = (_translet != null) ? _translet.hasIdCall()
 555                                                          : false;
 556 
 557                  if (_dtmManager == null) {
 558                      _dtmManager =
 559                          _tfactory.createNewDTMManagerInstance();
 560                      _dtmManager.setServicesMechnism(_useServicesMechanism);
 561                  }
 562                  dom = (DOM)_dtmManager.getDTM(source, false, wsfilter, true,
 563                                               false, false, 0, hasIdCall);
 564             } else if (_dom != null) {
 565                  dom = _dom;
 566                  _dom = null;  // use only once, so reset to 'null'
 567             } else {
 568                  return null;
 569             }
 570 
 571             if (!_isIdentity) {
 572                 // Give the translet the opportunity to make a prepass of
 573                 // the document, in case it can extract useful information early
 574                 _translet.prepassDocument(dom);
 575             }
 576 
 577             return dom;
 578 
 579         }
 580         catch (Exception e) {
 581             if (_errorListener != null) {
 582                 postErrorToListener(e.getMessage());
 583             }
 584             throw new TransformerException(e);
 585         }
 586     }
 587 
 588     /**
 589      * Returns the {@link com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl}
 590      * object that create this <code>Transformer</code>.
 591      */
 592     protected TransformerFactoryImpl getTransformerFactory() {
 593         return _tfactory;
 594     }
 595 
 596     /**
 597      * Returns the {@link com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory}
 598      * object that create the <code>TransletOutputHandler</code>.
 599      */
 600     protected TransletOutputHandlerFactory getTransletOutputHandlerFactory() {
 601         return _tohFactory;
 602     }
 603 
 604     private void transformIdentity(Source source, SerializationHandler handler)
 605         throws Exception
 606     {
 607         // Get systemId from source
 608         if (source != null) {
 609             _sourceSystemId = source.getSystemId();
 610         }
 611 
 612         if (source instanceof StreamSource) {
 613             final StreamSource stream = (StreamSource) source;
 614             final InputStream streamInput = stream.getInputStream();
 615             final Reader streamReader = stream.getReader();
 616             final XMLReader reader = _readerManager.getXMLReader();
 617 
 618             try {
 619                 // Hook up reader and output handler
 620                 try {
 621                     reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
 622                     reader.setFeature(NAMESPACE_PREFIXES_FEATURE, true);
 623                 } catch (SAXException e) {
 624                     // Falls through
 625                 }
 626                 reader.setContentHandler(handler);
 627 
 628                 // Create input source from source
 629                 InputSource input;
 630                 if (streamInput != null) {
 631                     input = new InputSource(streamInput);
 632                     input.setSystemId(_sourceSystemId);
 633                 }
 634                 else if (streamReader != null) {
 635                     input = new InputSource(streamReader);
 636                     input.setSystemId(_sourceSystemId);
 637                 }
 638                 else if (_sourceSystemId != null) {
 639                     input = new InputSource(_sourceSystemId);
 640                 }
 641                 else {
 642                     ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR);
 643                     throw new TransformerException(err.toString());
 644                 }
 645 
 646                 // Start pushing SAX events
 647                 reader.parse(input);
 648             } finally {
 649                 _readerManager.releaseXMLReader(reader);
 650             }
 651         } else if (source instanceof SAXSource) {
 652             final SAXSource sax = (SAXSource) source;
 653             XMLReader reader = sax.getXMLReader();
 654             final InputSource input = sax.getInputSource();
 655             boolean userReader = true;
 656 
 657             try {
 658                 // Create a reader if not set by user
 659                 if (reader == null) {
 660                     reader = _readerManager.getXMLReader();
 661                     userReader = false;
 662                 }
 663 
 664                 // Hook up reader and output handler
 665                 try {
 666                     reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
 667                     reader.setFeature(NAMESPACE_PREFIXES_FEATURE, true);
 668                 } catch (SAXException e) {
 669                     // Falls through
 670                 }
 671                 reader.setContentHandler(handler);
 672 
 673                 // Start pushing SAX events
 674                 reader.parse(input);
 675             } finally {
 676                 if (!userReader) {
 677                     _readerManager.releaseXMLReader(reader);
 678                 }
 679             }
 680         } else if (source instanceof StAXSource) {
 681             final StAXSource staxSource = (StAXSource)source;
 682             StAXEvent2SAX staxevent2sax;
 683             StAXStream2SAX staxStream2SAX;
 684             if (staxSource.getXMLEventReader() != null) {
 685                 final XMLEventReader xmlEventReader = staxSource.getXMLEventReader();
 686                 staxevent2sax = new StAXEvent2SAX(xmlEventReader);
 687                 staxevent2sax.setContentHandler(handler);
 688                 staxevent2sax.parse();
 689                 handler.flushPending();
 690             } else if (staxSource.getXMLStreamReader() != null) {
 691                 final XMLStreamReader xmlStreamReader = staxSource.getXMLStreamReader();
 692                 staxStream2SAX = new StAXStream2SAX(xmlStreamReader);
 693                 staxStream2SAX.setContentHandler(handler);
 694                 staxStream2SAX.parse();
 695                 handler.flushPending();
 696             }
 697         } else if (source instanceof DOMSource) {
 698             final DOMSource domsrc = (DOMSource) source;
 699             new DOM2TO(domsrc.getNode(), handler).parse();
 700         } else if (source instanceof XSLTCSource) {
 701             final DOM dom = ((XSLTCSource) source).getDOM(null, _translet);
 702             ((SAXImpl)dom).copy(handler);
 703         } else {
 704             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR);
 705             throw new TransformerException(err.toString());
 706         }
 707     }
 708 
 709     /**
 710      * Internal transformation method - uses the internal APIs of XSLTC
 711      */
 712     private void transform(Source source, SerializationHandler handler,
 713         String encoding) throws TransformerException
 714     {
 715         try {
 716             /*
 717              * According to JAXP1.2, new SAXSource()/StreamSource()
 718              * should create an empty input tree, with a default root node.
 719              * new DOMSource()creates an empty document using DocumentBuilder.
 720              * newDocument(); Use DocumentBuilder.newDocument() for all 3
 721              * situations, since there is no clear spec. how to create
 722              * an empty tree when both SAXSource() and StreamSource() are used.
 723              */
 724             if ((source instanceof StreamSource && source.getSystemId()==null
 725                 && ((StreamSource)source).getInputStream()==null &&
 726                 ((StreamSource)source).getReader()==null)||
 727                 (source instanceof SAXSource &&
 728                 ((SAXSource)source).getInputSource()==null &&
 729                 ((SAXSource)source).getXMLReader()==null )||
 730                 (source instanceof DOMSource &&
 731                 ((DOMSource)source).getNode()==null)){
 732                         DocumentBuilderFactory builderF = FactoryImpl.getDOMFactory(_useServicesMechanism);
 733                         DocumentBuilder builder = builderF.newDocumentBuilder();
 734                         String systemID = source.getSystemId();
 735                         source = new DOMSource(builder.newDocument());
 736 
 737                         // Copy system ID from original, empty Source to new
 738                         if (systemID != null) {
 739                           source.setSystemId(systemID);
 740                         }
 741             }
 742             if (_isIdentity) {
 743                 transformIdentity(source, handler);
 744             } else {
 745                 _translet.transform(getDOM(source), handler);
 746             }
 747         } catch (TransletException e) {
 748             if (_errorListener != null) postErrorToListener(e.getMessage());
 749             throw new TransformerException(e);
 750         } catch (RuntimeException e) {
 751             if (_errorListener != null) postErrorToListener(e.getMessage());
 752             throw new TransformerException(e);
 753         } catch (Exception e) {
 754             if (_errorListener != null) postErrorToListener(e.getMessage());
 755             throw new TransformerException(e);
 756         } finally {
 757             _dtmManager = null;
 758         }
 759 
 760         // If we create an output stream for the Result, we need to close it after the transformation.
 761         if (_ostream != null) {
 762             try {
 763                 _ostream.close();
 764             }
 765             catch (IOException e) {}
 766             _ostream = null;
 767         }
 768     }
 769 
 770     /**
 771      * Implements JAXP's Transformer.getErrorListener()
 772      * Get the error event handler in effect for the transformation.
 773      *
 774      * @return The error event handler currently in effect
 775      */
 776     @Override
 777     public ErrorListener getErrorListener() {
 778         return _errorListener;
 779     }
 780 
 781     /**
 782      * Implements JAXP's Transformer.setErrorListener()
 783      * Set the error event listener in effect for the transformation.
 784      * Register a message handler in the translet in order to forward
 785      * xsl:messages to error listener.
 786      *
 787      * @param listener The error event listener to use
 788      * @throws IllegalArgumentException
 789      */
 790     @Override
 791     public void setErrorListener(ErrorListener listener)
 792         throws IllegalArgumentException {
 793         if (listener == null) {
 794             ErrorMsg err = new ErrorMsg(ErrorMsg.ERROR_LISTENER_NULL_ERR,
 795                                         "Transformer");
 796             throw new IllegalArgumentException(err.toString());
 797         }
 798         _errorListener = listener;
 799 
 800         // Register a message handler to report xsl:messages
 801     if (_translet != null)
 802         _translet.setMessageHandler(new MessageHandler(_errorListener));
 803     }
 804 
 805     /**
 806      * Inform TrAX error listener of an error
 807      */
 808     private void postErrorToListener(String message) {
 809         try {
 810             _errorListener.error(new TransformerException(message));
 811         }
 812         catch (TransformerException e) {
 813             // ignored - transformation cannot be continued
 814         }
 815     }
 816 
 817     /**
 818      * Inform TrAX error listener of a warning
 819      */
 820     private void postWarningToListener(String message) {
 821         try {
 822             _errorListener.warning(new TransformerException(message));
 823         }
 824         catch (TransformerException e) {
 825             // ignored - transformation cannot be continued
 826         }
 827     }
 828 
 829     /**
 830      * The translet stores all CDATA sections set in the <xsl:output> element
 831      * in a Hashtable. This method will re-construct the whitespace separated
 832      * list of elements given in the <xsl:output> element.
 833      */
 834     private String makeCDATAString(Hashtable cdata) {
 835         // Return a 'null' string if no CDATA section elements were specified
 836         if (cdata == null) return null;
 837 
 838         final StringBuilder result = new StringBuilder();
 839 
 840         // Get an enumeration of all the elements in the hashtable
 841         Enumeration elements = cdata.keys();
 842         if (elements.hasMoreElements()) {
 843             result.append((String)elements.nextElement());
 844             while (elements.hasMoreElements()) {
 845                 String element = (String)elements.nextElement();
 846                 result.append(' ');
 847                 result.append(element);
 848             }
 849         }
 850 
 851         return(result.toString());
 852     }
 853 
 854     /**
 855      * Implements JAXP's Transformer.getOutputProperties().
 856      * Returns a copy of the output properties for the transformation. This is
 857      * a set of layered properties. The first layer contains properties set by
 858      * calls to setOutputProperty() and setOutputProperties() on this class,
 859      * and the output settings defined in the stylesheet's <xsl:output>
 860      * element makes up the second level, while the default XSLT output
 861      * settings are returned on the third level.
 862      *
 863      * @return Properties in effect for this Transformer
 864      */
 865     @Override
 866     public Properties getOutputProperties() {
 867         return (Properties) _properties.clone();
 868     }
 869 
 870     /**
 871      * Implements JAXP's Transformer.getOutputProperty().
 872      * Get an output property that is in effect for the transformation. The
 873      * property specified may be a property that was set with setOutputProperty,
 874      * or it may be a property specified in the stylesheet.
 875      *
 876      * @param name A non-null string that contains the name of the property
 877      * @throws IllegalArgumentException if the property name is not known
 878      */
 879     @Override
 880     public String getOutputProperty(String name)
 881         throws IllegalArgumentException
 882     {
 883         if (!validOutputProperty(name)) {
 884             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
 885             throw new IllegalArgumentException(err.toString());
 886         }
 887         return _properties.getProperty(name);
 888     }
 889 
 890     /**
 891      * Implements JAXP's Transformer.setOutputProperties().
 892      * Set the output properties for the transformation. These properties
 893      * will override properties set in the Templates with xsl:output.
 894      * Unrecognised properties will be quitely ignored.
 895      *
 896      * @param properties The properties to use for the Transformer
 897      * @throws IllegalArgumentException Never, errors are ignored
 898      */
 899     @Override
 900     public void setOutputProperties(Properties properties)
 901         throws IllegalArgumentException
 902     {
 903         if (properties != null) {
 904             final Enumeration names = properties.propertyNames();
 905 
 906             while (names.hasMoreElements()) {
 907                 final String name = (String) names.nextElement();
 908 
 909                 // Ignore lower layer properties
 910                 if (isDefaultProperty(name, properties)) continue;
 911 
 912                 if (validOutputProperty(name)) {
 913                     _properties.setProperty(name, properties.getProperty(name));
 914                 }
 915                 else {
 916                     ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
 917                     throw new IllegalArgumentException(err.toString());
 918                 }
 919             }
 920         }
 921         else {
 922             _properties = _propertiesClone;
 923         }
 924     }
 925 
 926     /**
 927      * Implements JAXP's Transformer.setOutputProperty().
 928      * Get an output property that is in effect for the transformation. The
 929      * property specified may be a property that was set with
 930      * setOutputProperty(), or it may be a property specified in the stylesheet.
 931      *
 932      * @param name The name of the property to set
 933      * @param value The value to assign to the property
 934      * @throws IllegalArgumentException Never, errors are ignored
 935      */
 936     @Override
 937     public void setOutputProperty(String name, String value)
 938         throws IllegalArgumentException
 939     {
 940         if (!validOutputProperty(name)) {
 941             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
 942             throw new IllegalArgumentException(err.toString());
 943         }
 944         _properties.setProperty(name, value);
 945     }
 946 
 947     /**
 948      * Internal method to pass any properties to the translet prior to
 949      * initiating the transformation
 950      */
 951     private void transferOutputProperties(AbstractTranslet translet)
 952     {
 953         // Return right now if no properties are set
 954         if (_properties == null) return;
 955 
 956         // Get a list of all the defined properties
 957         Enumeration names = _properties.propertyNames();
 958         while (names.hasMoreElements()) {
 959             // Note the use of get() instead of getProperty()
 960             String name  = (String) names.nextElement();
 961             String value = (String) _properties.get(name);
 962 
 963             // Ignore default properties
 964             if (value == null) continue;
 965 
 966             // Pass property value to translet - override previous setting
 967             if (name.equals(OutputKeys.ENCODING)) {
 968                 translet._encoding = value;
 969             }
 970             else if (name.equals(OutputKeys.METHOD)) {
 971                 translet._method = value;
 972             }
 973             else if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) {
 974                 translet._doctypePublic = value;
 975             }
 976             else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) {
 977                 translet._doctypeSystem = value;
 978             }
 979             else if (name.equals(OutputKeys.MEDIA_TYPE)) {
 980                 translet._mediaType = value;
 981             }
 982             else if (name.equals(OutputKeys.STANDALONE)) {
 983                 translet._standalone = value;
 984             }
 985             else if (name.equals(OutputKeys.VERSION)) {
 986                 translet._version = value;
 987             }
 988             else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) {
 989                 translet._omitHeader =
 990                     (value != null && value.toLowerCase().equals("yes"));
 991             }
 992             else if (name.equals(OutputKeys.INDENT)) {
 993                 translet._indent =
 994                     (value != null && value.toLowerCase().equals("yes"));
 995             }
 996             else if (name.equals(OutputPropertiesFactory.S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL +"indent-amount")) {
 997                  if (value != null) {
 998                      translet._indentamount = Integer.parseInt(value);
 999                  }
1000             }
1001             else if (name.equals(OutputPropertiesFactory.S_BUILTIN_EXTENSIONS_UNIVERSAL +"indent-amount")) {
1002                  if (value != null) {
1003                      translet._indentamount = Integer.parseInt(value);
1004                  }
1005             }
1006             else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
1007                 if (value != null) {
1008                     translet._cdata = null; // clear previous setting
1009                     StringTokenizer e = new StringTokenizer(value);
1010                     while (e.hasMoreTokens()) {
1011                         translet.addCdataElement(e.nextToken());
1012                     }
1013                 }
1014             }
1015             else if (name.equals(OutputPropertiesFactory.ORACLE_IS_STANDALONE)) {
1016                  if (value != null && value.equals("yes")) {
1017                      translet._isStandalone = true;
1018                  }
1019             }
1020         }
1021     }
1022 
1023     /**
1024      * This method is used to pass any properties to the output handler
1025      * when running the identity transform.
1026      */
1027     public void transferOutputProperties(SerializationHandler handler)
1028     {
1029         // Return right now if no properties are set
1030         if (_properties == null) return;
1031 
1032         String doctypePublic = null;
1033         String doctypeSystem = null;
1034 
1035         // Get a list of all the defined properties
1036         Enumeration names = _properties.propertyNames();
1037         while (names.hasMoreElements()) {
1038             // Note the use of get() instead of getProperty()
1039             String name  = (String) names.nextElement();
1040             String value = (String) _properties.get(name);
1041 
1042             // Ignore default properties
1043             if (value == null) continue;
1044 
1045             // Pass property value to translet - override previous setting
1046             if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) {
1047                 doctypePublic = value;
1048             }
1049             else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) {
1050                 doctypeSystem = value;
1051             }
1052             else if (name.equals(OutputKeys.MEDIA_TYPE)) {
1053                 handler.setMediaType(value);
1054             }
1055             else if (name.equals(OutputKeys.STANDALONE)) {
1056                 handler.setStandalone(value);
1057             }
1058             else if (name.equals(OutputKeys.VERSION)) {
1059                 handler.setVersion(value);
1060             }
1061             else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) {
1062                 handler.setOmitXMLDeclaration(
1063                     value != null && value.toLowerCase().equals("yes"));
1064             }
1065             else if (name.equals(OutputKeys.INDENT)) {
1066                 handler.setIndent(
1067                     value != null && value.toLowerCase().equals("yes"));
1068             }
1069             else if (name.equals(OutputPropertiesFactory.S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL +"indent-amount")) {
1070                 if (value != null) {
1071                     handler.setIndentAmount(Integer.parseInt(value));
1072                 }
1073             }
1074             else if (name.equals(OutputPropertiesFactory.S_BUILTIN_EXTENSIONS_UNIVERSAL +"indent-amount")) {
1075                 if (value != null) {
1076                     handler.setIndentAmount(Integer.parseInt(value));
1077                 }
1078             }
1079             else if (name.equals(OutputPropertiesFactory.ORACLE_IS_STANDALONE)) {
1080                 if (value != null && value.equals("yes")) {
1081                     handler.setIsStandalone(true);
1082                 }
1083             }
1084             else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
1085                 if (value != null) {
1086                     StringTokenizer e = new StringTokenizer(value);
1087                     Vector uriAndLocalNames = null;
1088                     while (e.hasMoreTokens()) {
1089                         final String token = e.nextToken();
1090 
1091                         // look for the last colon, as the String may be
1092                         // something like "http://abc.com:local"
1093                         int lastcolon = token.lastIndexOf(':');
1094                         String uri;
1095                         String localName;
1096                         if (lastcolon > 0) {
1097                             uri = token.substring(0, lastcolon);
1098                             localName = token.substring(lastcolon+1);
1099                         } else {
1100                             // no colon at all, lets hope this is the
1101                             // local name itself then
1102                             uri = null;
1103                             localName = token;
1104                         }
1105 
1106                         if (uriAndLocalNames == null) {
1107                             uriAndLocalNames = new Vector();
1108                         }
1109                         // add the uri/localName as a pair, in that order
1110                         uriAndLocalNames.addElement(uri);
1111                         uriAndLocalNames.addElement(localName);
1112                     }
1113                     handler.setCdataSectionElements(uriAndLocalNames);
1114                 }
1115             }
1116         }
1117 
1118         // Call setDoctype() if needed
1119         if (doctypePublic != null || doctypeSystem != null) {
1120             handler.setDoctype(doctypeSystem, doctypePublic);
1121         }
1122     }
1123 
1124     /**
1125      * Internal method to create the initial set of properties. There
1126      * are two layers of properties: the default layer and the base layer.
1127      * The latter contains properties defined in the stylesheet or by
1128      * the user using this API.
1129      */
1130     private Properties createOutputProperties(Properties outputProperties) {
1131         final Properties defaults = new Properties();
1132         setDefaults(defaults, "xml");
1133 
1134         // Copy propeties set in stylesheet to base
1135         final Properties base = new Properties(defaults);
1136         if (outputProperties != null) {
1137             final Enumeration names = outputProperties.propertyNames();
1138             while (names.hasMoreElements()) {
1139                 final String name = (String) names.nextElement();
1140                 base.setProperty(name, outputProperties.getProperty(name));
1141             }
1142         }
1143         else {
1144             base.setProperty(OutputKeys.ENCODING, _translet._encoding);
1145             if (_translet._method != null)
1146                 base.setProperty(OutputKeys.METHOD, _translet._method);
1147         }
1148 
1149         // Update defaults based on output method
1150         final String method = base.getProperty(OutputKeys.METHOD);
1151         if (method != null) {
1152             if (method.equals("html")) {
1153                 setDefaults(defaults,"html");
1154             }
1155             else if (method.equals("text")) {
1156                 setDefaults(defaults,"text");
1157             }
1158         }
1159 
1160         return base;
1161     }
1162 
1163         /**
1164          * Internal method to get the default properties from the
1165          * serializer factory and set them on the property object.
1166          * @param props a java.util.Property object on which the properties are set.
1167          * @param method The output method type, one of "xml", "text", "html" ...
1168          */
1169         private void setDefaults(Properties props, String method)
1170         {
1171                 final Properties method_props =
1172                         OutputPropertiesFactory.getDefaultMethodProperties(method);
1173                 {
1174                         final Enumeration names = method_props.propertyNames();
1175                         while (names.hasMoreElements())
1176                         {
1177                                 final String name = (String)names.nextElement();
1178                                 props.setProperty(name, method_props.getProperty(name));
1179                         }
1180                 }
1181         }
1182     /**
1183      * Verifies if a given output property name is a property defined in
1184      * the JAXP 1.1 / TrAX spec
1185      */
1186     private boolean validOutputProperty(String name) {
1187         return (name.equals(OutputKeys.ENCODING) ||
1188                 name.equals(OutputKeys.METHOD) ||
1189                 name.equals(OutputKeys.INDENT) ||
1190                 name.equals(OutputKeys.DOCTYPE_PUBLIC) ||
1191                 name.equals(OutputKeys.DOCTYPE_SYSTEM) ||
1192                 name.equals(OutputKeys.CDATA_SECTION_ELEMENTS) ||
1193                 name.equals(OutputKeys.MEDIA_TYPE) ||
1194                 name.equals(OutputKeys.OMIT_XML_DECLARATION)   ||
1195                 name.equals(OutputKeys.STANDALONE) ||
1196                 name.equals(OutputKeys.VERSION) ||
1197                 name.equals(OutputPropertiesFactory.ORACLE_IS_STANDALONE) ||
1198                 name.charAt(0) == '{');
1199     }
1200 
1201     /**
1202      * Checks if a given output property is default (2nd layer only)
1203      */
1204     private boolean isDefaultProperty(String name, Properties properties) {
1205         return (properties.get(name) == null);
1206     }
1207 
1208     /**
1209      * Implements JAXP's Transformer.setParameter()
1210      * Add a parameter for the transformation. The parameter is simply passed
1211      * on to the translet - no validation is performed - so any unused
1212      * parameters are quitely ignored by the translet.
1213      *
1214      * @param name The name of the parameter
1215      * @param value The value to assign to the parameter
1216      */
1217     @Override
1218     public void setParameter(String name, Object value) {
1219 
1220         if (value == null) {
1221             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_INVALID_SET_PARAM_VALUE, name);
1222             throw new IllegalArgumentException(err.toString());
1223         }
1224 
1225         if (_isIdentity) {
1226             if (_parameters == null) {
1227                 _parameters = new Hashtable();
1228             }
1229             _parameters.put(name, value);
1230         }
1231         else {
1232             _translet.addParameter(name, value);
1233         }
1234     }
1235 
1236     /**
1237      * Implements JAXP's Transformer.clearParameters()
1238      * Clear all parameters set with setParameter. Clears the translet's
1239      * parameter stack.
1240      */
1241     @Override
1242     public void clearParameters() {
1243         if (_isIdentity && _parameters != null) {
1244             _parameters.clear();
1245         }
1246         else {
1247             _translet.clearParameters();
1248         }
1249     }
1250 
1251     /**
1252      * Implements JAXP's Transformer.getParameter()
1253      * Returns the value of a given parameter. Note that the translet will not
1254      * keep values for parameters that were not defined in the stylesheet.
1255      *
1256      * @param name The name of the parameter
1257      * @return An object that contains the value assigned to the parameter
1258      */
1259     @Override
1260     public final Object getParameter(String name) {
1261         if (_isIdentity) {
1262             return (_parameters != null) ? _parameters.get(name) : null;
1263         }
1264         else {
1265             return _translet.getParameter(name);
1266         }
1267     }
1268 
1269     /**
1270      * Implements JAXP's Transformer.getURIResolver()
1271      * Set the object currently used to resolve URIs used in document().
1272      *
1273      * @return  The URLResolver object currently in use
1274      */
1275     @Override
1276     public URIResolver getURIResolver() {
1277         return _uriResolver;
1278     }
1279 
1280     /**
1281      * Implements JAXP's Transformer.setURIResolver()
1282      * Set an object that will be used to resolve URIs used in document().
1283      *
1284      * @param resolver The URIResolver to use in document()
1285      */
1286     @Override
1287     public void setURIResolver(URIResolver resolver) {
1288         _uriResolver = resolver;
1289     }
1290 
1291     /**
1292      * This class should only be used as a DOMCache for the translet if the
1293      * URIResolver has been set.
1294      *
1295      * The method implements XSLTC's DOMCache interface, which is used to
1296      * plug in an external document loader into a translet. This method acts
1297      * as an adapter between TrAX's URIResolver interface and XSLTC's
1298      * DOMCache interface. This approach is simple, but removes the
1299      * possibility of using external document caches with XSLTC.
1300      *
1301      * @param baseURI The base URI used by the document call.
1302      * @param href The href argument passed to the document function.
1303      * @param translet A reference to the translet requesting the document
1304      */
1305     @Override
1306     public DOM retrieveDocument(String baseURI, String href, Translet translet) {
1307         try {
1308             // Argument to document function was: document('');
1309             if (href.length() == 0) {
1310                 href = baseURI;
1311             }
1312 
1313             /*
1314              *  Fix for bug 24188
1315              *  Incase the _uriResolver.resolve(href,base) is null
1316              *  try to still  retrieve the document before returning null
1317              *  and throwing the FileNotFoundException in
1318              *  com.sun.org.apache.xalan.internal.xsltc.dom.LoadDocument
1319              *
1320              */
1321             Source resolvedSource = _uriResolver.resolve(href, baseURI);
1322             if (resolvedSource == null)  {
1323                 StreamSource streamSource = new StreamSource(
1324                      SystemIDResolver.getAbsoluteURI(href, baseURI));
1325                 return getDOM(streamSource) ;
1326             }
1327 
1328             return getDOM(resolvedSource);
1329         }
1330         catch (TransformerException e) {
1331             if (_errorListener != null)
1332                 postErrorToListener("File not found: " + e.getMessage());
1333             return(null);
1334         }
1335     }
1336 
1337     /**
1338      * Receive notification of a recoverable error.
1339      * The transformer must continue to provide normal parsing events after
1340      * invoking this method. It should still be possible for the application
1341      * to process the document through to the end.
1342      *
1343      * @param e The warning information encapsulated in a transformer
1344      * exception.
1345      * @throws TransformerException if the application chooses to discontinue
1346      * the transformation (always does in our case).
1347      */
1348     @Override
1349     public void error(TransformerException e)
1350         throws TransformerException
1351     {
1352         Throwable wrapped = e.getException();
1353         if (wrapped != null) {
1354             System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG,
1355                                             e.getMessageAndLocation(),
1356                                             wrapped.getMessage()));
1357         } else {
1358             System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG,
1359                                             e.getMessageAndLocation()));
1360         }
1361         throw e;
1362     }
1363 
1364     /**
1365      * Receive notification of a non-recoverable error.
1366      * The application must assume that the transformation cannot continue
1367      * after the Transformer has invoked this method, and should continue
1368      * (if at all) only to collect addition error messages. In fact,
1369      * Transformers are free to stop reporting events once this method has
1370      * been invoked.
1371      *
1372      * @param e The warning information encapsulated in a transformer
1373      * exception.
1374      * @throws TransformerException if the application chooses to discontinue
1375      * the transformation (always does in our case).
1376      */
1377     @Override
1378     public void fatalError(TransformerException e)
1379         throws TransformerException
1380     {
1381         Throwable wrapped = e.getException();
1382         if (wrapped != null) {
1383             System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG,
1384                                             e.getMessageAndLocation(),
1385                                             wrapped.getMessage()));
1386         } else {
1387             System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG,
1388                                             e.getMessageAndLocation()));
1389         }
1390         throw e;
1391     }
1392 
1393     /**
1394      * Receive notification of a warning.
1395      * Transformers can use this method to report conditions that are not
1396      * errors or fatal errors. The default behaviour is to take no action.
1397      * After invoking this method, the Transformer must continue with the
1398      * transformation. It should still be possible for the application to
1399      * process the document through to the end.
1400      *
1401      * @param e The warning information encapsulated in a transformer
1402      * exception.
1403      * @throws TransformerException if the application chooses to discontinue
1404      * the transformation (never does in our case).
1405      */
1406     @Override
1407     public void warning(TransformerException e)
1408         throws TransformerException
1409     {
1410         Throwable wrapped = e.getException();
1411         if (wrapped != null) {
1412             System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG,
1413                                             e.getMessageAndLocation(),
1414                                             wrapped.getMessage()));
1415         } else {
1416             System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG,
1417                                             e.getMessageAndLocation()));
1418         }
1419     }
1420 
1421     /**
1422      * This method resets  the Transformer to its original configuration
1423      * Transformer code is reset to the same state it was when it was
1424      * created
1425      * @since 1.5
1426      */
1427     @Override
1428     public void reset() {
1429 
1430         _method = null;
1431         _encoding = null;
1432         _sourceSystemId = null;
1433         _errorListener = this;
1434         _uriResolver = null;
1435         _dom = null;
1436         _parameters = null;
1437         _indentNumber = 0;
1438         setOutputProperties (null);
1439         _tohFactory = null;
1440         _ostream = null;
1441 
1442     }
1443 }