Home | History | Annotate | Download | only in processor
      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: TransformerFactoryImpl.java 468640 2006-10-28 06:53:53Z minchau $
     20  */
     21 package org.apache.xalan.processor;
     22 
     23 import java.io.BufferedInputStream;
     24 import java.io.IOException;
     25 import java.io.InputStream;
     26 import java.util.Enumeration;
     27 import java.util.Properties;
     28 
     29 import javax.xml.XMLConstants;
     30 import javax.xml.transform.ErrorListener;
     31 import javax.xml.transform.Source;
     32 import javax.xml.transform.Templates;
     33 import javax.xml.transform.Transformer;
     34 import javax.xml.transform.TransformerConfigurationException;
     35 import javax.xml.transform.TransformerException;
     36 import javax.xml.transform.URIResolver;
     37 import javax.xml.transform.dom.DOMResult;
     38 import javax.xml.transform.dom.DOMSource;
     39 import javax.xml.transform.sax.SAXResult;
     40 import javax.xml.transform.sax.SAXSource;
     41 import javax.xml.transform.sax.SAXTransformerFactory;
     42 import javax.xml.transform.sax.TemplatesHandler;
     43 import javax.xml.transform.sax.TransformerHandler;
     44 import javax.xml.transform.stream.StreamResult;
     45 import javax.xml.transform.stream.StreamSource;
     46 
     47 import org.apache.xalan.res.XSLMessages;
     48 import org.apache.xalan.res.XSLTErrorResources;
     49 import org.apache.xalan.transformer.TrAXFilter;
     50 import org.apache.xalan.transformer.TransformerIdentityImpl;
     51 import org.apache.xalan.transformer.TransformerImpl;
     52 import org.apache.xalan.transformer.XalanProperties;
     53 
     54 import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM;
     55 import org.apache.xml.utils.DefaultErrorHandler;
     56 import org.apache.xml.utils.SystemIDResolver;
     57 import org.apache.xml.utils.TreeWalker;
     58 import org.apache.xml.utils.StylesheetPIHandler;
     59 import org.apache.xml.utils.StopParseException;
     60 
     61 import org.w3c.dom.Node;
     62 
     63 import org.xml.sax.InputSource;
     64 import org.xml.sax.XMLFilter;
     65 import org.xml.sax.XMLReader;
     66 import org.xml.sax.helpers.XMLReaderFactory;
     67 
     68 /**
     69  * The TransformerFactoryImpl, which implements the TRaX TransformerFactory
     70  * interface, processes XSLT stylesheets into a Templates object
     71  * (a StylesheetRoot).
     72  */
     73 public class TransformerFactoryImpl extends SAXTransformerFactory
     74 {
     75   /**
     76    * The path/filename of the property file: XSLTInfo.properties
     77    * Maintenance note: see also
     78    * <code>org.apache.xpath.functions.FuncSystemProperty.XSLT_PROPERTIES</code>
     79    */
     80   public static final String XSLT_PROPERTIES =
     81     "org/apache/xalan/res/XSLTInfo.properties";
     82 
     83   /**
     84    * <p>State of secure processing feature.</p>
     85    */
     86   private boolean m_isSecureProcessing = false;
     87 
     88   /**
     89    * Constructor TransformerFactoryImpl
     90    *
     91    */
     92   public TransformerFactoryImpl()
     93   {
     94   }
     95 
     96   /** Static string to be used for incremental feature */
     97   public static final String FEATURE_INCREMENTAL =
     98                              "http://xml.apache.org/xalan/features/incremental";
     99 
    100   /** Static string to be used for optimize feature */
    101   public static final String FEATURE_OPTIMIZE =
    102                              "http://xml.apache.org/xalan/features/optimize";
    103 
    104   /** Static string to be used for source_location feature */
    105   public static final String FEATURE_SOURCE_LOCATION =
    106                              XalanProperties.SOURCE_LOCATION;
    107 
    108   public javax.xml.transform.Templates processFromNode(Node node)
    109           throws TransformerConfigurationException
    110   {
    111 
    112     try
    113     {
    114       TemplatesHandler builder = newTemplatesHandler();
    115       TreeWalker walker = new TreeWalker(builder,
    116                                          new org.apache.xml.utils.DOM2Helper(),
    117                                          builder.getSystemId());
    118 
    119       walker.traverse(node);
    120 
    121       return builder.getTemplates();
    122     }
    123     catch (org.xml.sax.SAXException se)
    124     {
    125       if (m_errorListener != null)
    126       {
    127         try
    128         {
    129           m_errorListener.fatalError(new TransformerException(se));
    130         }
    131         catch (TransformerConfigurationException ex)
    132         {
    133           throw ex;
    134         }
    135         catch (TransformerException ex)
    136         {
    137           throw new TransformerConfigurationException(ex);
    138         }
    139 
    140         return null;
    141       }
    142       else
    143       {
    144 
    145         // Should remove this later... but right now diagnostics from
    146         // TransformerConfigurationException are not good.
    147         // se.printStackTrace();
    148         throw new TransformerConfigurationException(XSLMessages.createMessage(XSLTErrorResources.ER_PROCESSFROMNODE_FAILED, null), se);
    149         //"processFromNode failed", se);
    150       }
    151     }
    152     catch (TransformerConfigurationException tce)
    153     {
    154       // Assume it's already been reported to the error listener.
    155       throw tce;
    156     }
    157    /* catch (TransformerException tce)
    158     {
    159       // Assume it's already been reported to the error listener.
    160       throw new TransformerConfigurationException(tce.getMessage(), tce);
    161     }*/
    162     catch (Exception e)
    163     {
    164       if (m_errorListener != null)
    165       {
    166         try
    167         {
    168           m_errorListener.fatalError(new TransformerException(e));
    169         }
    170         catch (TransformerConfigurationException ex)
    171         {
    172           throw ex;
    173         }
    174         catch (TransformerException ex)
    175         {
    176           throw new TransformerConfigurationException(ex);
    177         }
    178 
    179         return null;
    180       }
    181       else
    182       {
    183         // Should remove this later... but right now diagnostics from
    184         // TransformerConfigurationException are not good.
    185         // se.printStackTrace();
    186         throw new TransformerConfigurationException(XSLMessages.createMessage(XSLTErrorResources.ER_PROCESSFROMNODE_FAILED, null), e); //"processFromNode failed",
    187                                                     //e);
    188       }
    189     }
    190   }
    191 
    192   /**
    193    * The systemID that was specified in
    194    * processFromNode(Node node, String systemID).
    195    */
    196   private String m_DOMsystemID = null;
    197 
    198   /**
    199    * The systemID that was specified in
    200    * processFromNode(Node node, String systemID).
    201    *
    202    * @return The systemID, or null.
    203    */
    204   String getDOMsystemID()
    205   {
    206     return m_DOMsystemID;
    207   }
    208 
    209   /**
    210    * Process the stylesheet from a DOM tree, if the
    211    * processor supports the "http://xml.org/trax/features/dom/input"
    212    * feature.
    213    *
    214    * @param node A DOM tree which must contain
    215    * valid transform instructions that this processor understands.
    216    * @param systemID The systemID from where xsl:includes and xsl:imports
    217    * should be resolved from.
    218    *
    219    * @return A Templates object capable of being used for transformation purposes.
    220    *
    221    * @throws TransformerConfigurationException
    222    */
    223   javax.xml.transform.Templates processFromNode(Node node, String systemID)
    224           throws TransformerConfigurationException
    225   {
    226 
    227     m_DOMsystemID = systemID;
    228 
    229     return processFromNode(node);
    230   }
    231 
    232   /**
    233    * Get InputSource specification(s) that are associated with the
    234    * given document specified in the source param,
    235    * via the xml-stylesheet processing instruction
    236    * (see http://www.w3.org/TR/xml-stylesheet/), and that matches
    237    * the given criteria.  Note that it is possible to return several stylesheets
    238    * that match the criteria, in which case they are applied as if they were
    239    * a list of imports or cascades.
    240    *
    241    * <p>Note that DOM2 has it's own mechanism for discovering stylesheets.
    242    * Therefore, there isn't a DOM version of this method.</p>
    243    *
    244    *
    245    * @param source The XML source that is to be searched.
    246    * @param media The media attribute to be matched.  May be null, in which
    247    *              case the prefered templates will be used (i.e. alternate = no).
    248    * @param title The value of the title attribute to match.  May be null.
    249    * @param charset The value of the charset attribute to match.  May be null.
    250    *
    251    * @return A Source object capable of being used to create a Templates object.
    252    *
    253    * @throws TransformerConfigurationException
    254    */
    255   public Source getAssociatedStylesheet(
    256           Source source, String media, String title, String charset)
    257             throws TransformerConfigurationException
    258   {
    259 
    260     String baseID;
    261     InputSource isource = null;
    262     Node node = null;
    263     XMLReader reader = null;
    264 
    265     if (source instanceof DOMSource)
    266     {
    267       DOMSource dsource = (DOMSource) source;
    268 
    269       node = dsource.getNode();
    270       baseID = dsource.getSystemId();
    271     }
    272     else
    273     {
    274       isource = SAXSource.sourceToInputSource(source);
    275       baseID = isource.getSystemId();
    276     }
    277 
    278     // What I try to do here is parse until the first startElement
    279     // is found, then throw a special exception in order to terminate
    280     // the parse.
    281     StylesheetPIHandler handler = new StylesheetPIHandler(baseID, media,
    282                                     title, charset);
    283 
    284     // Use URIResolver. Patch from Dmitri Ilyin
    285     if (m_uriResolver != null)
    286     {
    287       handler.setURIResolver(m_uriResolver);
    288     }
    289 
    290     try
    291     {
    292       if (null != node)
    293       {
    294         TreeWalker walker = new TreeWalker(handler, new org.apache.xml.utils.DOM2Helper(), baseID);
    295 
    296         walker.traverse(node);
    297       }
    298       else
    299       {
    300 
    301         // Use JAXP1.1 ( if possible )
    302         try
    303         {
    304           javax.xml.parsers.SAXParserFactory factory =
    305             javax.xml.parsers.SAXParserFactory.newInstance();
    306 
    307           factory.setNamespaceAware(true);
    308 
    309           if (m_isSecureProcessing)
    310           {
    311             try
    312             {
    313               factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    314             }
    315             catch (org.xml.sax.SAXException e) {}
    316           }
    317 
    318           javax.xml.parsers.SAXParser jaxpParser = factory.newSAXParser();
    319 
    320           reader = jaxpParser.getXMLReader();
    321         }
    322         catch (javax.xml.parsers.ParserConfigurationException ex)
    323         {
    324           throw new org.xml.sax.SAXException(ex);
    325         }
    326         catch (javax.xml.parsers.FactoryConfigurationError ex1)
    327         {
    328           throw new org.xml.sax.SAXException(ex1.toString());
    329         }
    330         catch (NoSuchMethodError ex2){}
    331         catch (AbstractMethodError ame){}
    332 
    333         if (null == reader)
    334         {
    335           reader = XMLReaderFactory.createXMLReader();
    336         }
    337 
    338         if(m_isSecureProcessing)
    339         {
    340             reader.setFeature("http://xml.org/sax/features/external-general-entities",false);
    341         }
    342         // Need to set options!
    343         reader.setContentHandler(handler);
    344         reader.parse(isource);
    345       }
    346     }
    347     catch (StopParseException spe)
    348     {
    349 
    350       // OK, good.
    351     }
    352     catch (org.xml.sax.SAXException se)
    353     {
    354       throw new TransformerConfigurationException(
    355         "getAssociatedStylesheets failed", se);
    356     }
    357     catch (IOException ioe)
    358     {
    359       throw new TransformerConfigurationException(
    360         "getAssociatedStylesheets failed", ioe);
    361     }
    362 
    363     return handler.getAssociatedStylesheet();
    364   }
    365 
    366   /**
    367    * Create a new Transformer object that performs a copy
    368    * of the source to the result.
    369    *
    370    * @return A Transformer object that may be used to perform a transformation
    371    * in a single thread, never null.
    372    *
    373    * @throws TransformerConfigurationException May throw this during
    374    *            the parse when it is constructing the
    375    *            Templates object and fails.
    376    */
    377   public TemplatesHandler newTemplatesHandler()
    378           throws TransformerConfigurationException
    379   {
    380     return new StylesheetHandler(this);
    381   }
    382 
    383   /**
    384    * <p>Set a feature for this <code>TransformerFactory</code> and <code>Transformer</code>s
    385    * or <code>Template</code>s created by this factory.</p>
    386    *
    387    * <p>
    388    * Feature names are fully qualified {@link java.net.URI}s.
    389    * Implementations may define their own features.
    390    * An {@link TransformerConfigurationException} is thrown if this <code>TransformerFactory</code> or the
    391    * <code>Transformer</code>s or <code>Template</code>s it creates cannot support the feature.
    392    * It is possible for an <code>TransformerFactory</code> to expose a feature value but be unable to change its state.
    393    * </p>
    394    *
    395    * <p>See {@link javax.xml.transform.TransformerFactory} for full documentation of specific features.</p>
    396    *
    397    * @param name Feature name.
    398    * @param value Is feature state <code>true</code> or <code>false</code>.
    399    *
    400    * @throws TransformerConfigurationException if this <code>TransformerFactory</code>
    401    *   or the <code>Transformer</code>s or <code>Template</code>s it creates cannot support this feature.
    402    * @throws NullPointerException If the <code>name</code> parameter is null.
    403    */
    404   public void setFeature(String name, boolean value)
    405 	  throws TransformerConfigurationException {
    406 
    407   	// feature name cannot be null
    408   	if (name == null) {
    409   	    throw new NullPointerException(
    410                   XSLMessages.createMessage(
    411                       XSLTErrorResources.ER_SET_FEATURE_NULL_NAME, null));
    412   	}
    413 
    414   	// secure processing?
    415   	if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
    416   	    m_isSecureProcessing = value;
    417   	}
    418   	// This implementation does not support the setting of a feature other than
    419   	// the secure processing feature.
    420   	else
    421     {
    422       throw new TransformerConfigurationException(
    423           XSLMessages.createMessage(
    424             XSLTErrorResources.ER_UNSUPPORTED_FEATURE,
    425             new Object[] {name}));
    426     }
    427   }
    428 
    429   /**
    430    * Look up the value of a feature.
    431    * <p>The feature name is any fully-qualified URI.  It is
    432    * possible for an TransformerFactory to recognize a feature name but
    433    * to be unable to return its value; this is especially true
    434    * in the case of an adapter for a SAX1 Parser, which has
    435    * no way of knowing whether the underlying parser is
    436    * validating, for example.</p>
    437    *
    438    * @param name The feature name, which is a fully-qualified URI.
    439    * @return The current state of the feature (true or false).
    440    */
    441   public boolean getFeature(String name) {
    442 
    443     // feature name cannot be null
    444     if (name == null)
    445     {
    446     	throw new NullPointerException(
    447             XSLMessages.createMessage(
    448             XSLTErrorResources.ER_GET_FEATURE_NULL_NAME, null));
    449     }
    450 
    451     // Try first with identity comparison, which
    452     // will be faster.
    453     if ((DOMResult.FEATURE == name) || (DOMSource.FEATURE == name)
    454             || (SAXResult.FEATURE == name) || (SAXSource.FEATURE == name)
    455             || (StreamResult.FEATURE == name)
    456             || (StreamSource.FEATURE == name)
    457             || (SAXTransformerFactory.FEATURE == name)
    458             || (SAXTransformerFactory.FEATURE_XMLFILTER == name))
    459       return true;
    460     else if ((DOMResult.FEATURE.equals(name))
    461              || (DOMSource.FEATURE.equals(name))
    462              || (SAXResult.FEATURE.equals(name))
    463              || (SAXSource.FEATURE.equals(name))
    464              || (StreamResult.FEATURE.equals(name))
    465              || (StreamSource.FEATURE.equals(name))
    466              || (SAXTransformerFactory.FEATURE.equals(name))
    467              || (SAXTransformerFactory.FEATURE_XMLFILTER.equals(name)))
    468       return true;
    469     // secure processing?
    470     else if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING))
    471       return m_isSecureProcessing;
    472     else
    473       // unknown feature
    474       return false;
    475   }
    476 
    477   /**
    478    * Flag set by FEATURE_OPTIMIZE.
    479    * This feature specifies whether to Optimize stylesheet processing. By
    480    * default it is set to true.
    481    */
    482   private boolean m_optimize = true;
    483 
    484   /** Flag set by FEATURE_SOURCE_LOCATION.
    485    * This feature specifies whether the transformation phase should
    486    * keep track of line and column numbers for the input source
    487    * document. Note that this works only when that
    488    * information is available from the source -- in other words, if you
    489    * pass in a DOM, there's little we can do for you.
    490    *
    491    * The default is false. Setting it true may significantly
    492    * increase storage cost per node.
    493    */
    494   private boolean m_source_location = false;
    495 
    496   /**
    497    * Flag set by FEATURE_INCREMENTAL.
    498    * This feature specifies whether to produce output incrementally, rather than
    499    * waiting to finish parsing the input before generating any output. By
    500    * default this attribute is set to false.
    501    */
    502   private boolean m_incremental = false;
    503 
    504   /**
    505    * Allows the user to set specific attributes on the underlying
    506    * implementation.
    507    *
    508    * @param name The name of the attribute.
    509    * @param value The value of the attribute; Boolean or String="true"|"false"
    510    *
    511    * @throws IllegalArgumentException thrown if the underlying
    512    * implementation doesn't recognize the attribute.
    513    */
    514   public void setAttribute(String name, Object value)
    515           throws IllegalArgumentException
    516   {
    517     if (name.equals(FEATURE_INCREMENTAL))
    518     {
    519       if(value instanceof Boolean)
    520       {
    521         // Accept a Boolean object..
    522         m_incremental = ((Boolean)value).booleanValue();
    523       }
    524       else if(value instanceof String)
    525       {
    526         // .. or a String object
    527         m_incremental = (new Boolean((String)value)).booleanValue();
    528       }
    529       else
    530       {
    531         // Give a more meaningful error message
    532         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
    533       }
    534 	}
    535     else if (name.equals(FEATURE_OPTIMIZE))
    536     {
    537       if(value instanceof Boolean)
    538       {
    539         // Accept a Boolean object..
    540         m_optimize = ((Boolean)value).booleanValue();
    541       }
    542       else if(value instanceof String)
    543       {
    544         // .. or a String object
    545         m_optimize = (new Boolean((String)value)).booleanValue();
    546       }
    547       else
    548       {
    549         // Give a more meaningful error message
    550         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
    551       }
    552     }
    553 
    554     // Custom Xalan feature: annotate DTM with SAX source locator fields.
    555     // This gets used during SAX2DTM instantiation.
    556     //
    557     // %REVIEW% Should the name of this field really be in XalanProperties?
    558     // %REVIEW% I hate that it's a global static, but didn't want to change APIs yet.
    559     else if(name.equals(FEATURE_SOURCE_LOCATION))
    560     {
    561       if(value instanceof Boolean)
    562       {
    563         // Accept a Boolean object..
    564         m_source_location = ((Boolean)value).booleanValue();
    565       }
    566       else if(value instanceof String)
    567       {
    568         // .. or a String object
    569         m_source_location = (new Boolean((String)value)).booleanValue();
    570       }
    571       else
    572       {
    573         // Give a more meaningful error message
    574         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
    575       }
    576     }
    577 
    578     else
    579     {
    580       throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_SUPPORTED, new Object[]{name})); //name + "not supported");
    581     }
    582   }
    583 
    584   /**
    585    * Allows the user to retrieve specific attributes on the underlying
    586    * implementation.
    587    *
    588    * @param name The name of the attribute.
    589    * @return value The value of the attribute.
    590    *
    591    * @throws IllegalArgumentException thrown if the underlying
    592    * implementation doesn't recognize the attribute.
    593    */
    594   public Object getAttribute(String name) throws IllegalArgumentException
    595   {
    596     if (name.equals(FEATURE_INCREMENTAL))
    597     {
    598       return new Boolean(m_incremental);
    599     }
    600     else if (name.equals(FEATURE_OPTIMIZE))
    601     {
    602       return new Boolean(m_optimize);
    603     }
    604     else if (name.equals(FEATURE_SOURCE_LOCATION))
    605     {
    606       return new Boolean(m_source_location);
    607     }
    608     else
    609       throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_ATTRIB_VALUE_NOT_RECOGNIZED, new Object[]{name})); //name + " attribute not recognized");
    610   }
    611 
    612   /**
    613    * Create an XMLFilter that uses the given source as the
    614    * transformation instructions.
    615    *
    616    * @param src The source of the transformation instructions.
    617    *
    618    * @return An XMLFilter object, or null if this feature is not supported.
    619    *
    620    * @throws TransformerConfigurationException
    621    */
    622   public XMLFilter newXMLFilter(Source src)
    623           throws TransformerConfigurationException
    624   {
    625 
    626     Templates templates = newTemplates(src);
    627     if( templates==null ) return null;
    628 
    629     return newXMLFilter(templates);
    630   }
    631 
    632   /**
    633    * Create an XMLFilter that uses the given source as the
    634    * transformation instructions.
    635    *
    636    * @param templates non-null reference to Templates object.
    637    *
    638    * @return An XMLFilter object, or null if this feature is not supported.
    639    *
    640    * @throws TransformerConfigurationException
    641    */
    642   public XMLFilter newXMLFilter(Templates templates)
    643           throws TransformerConfigurationException
    644   {
    645     try
    646     {
    647       return new TrAXFilter(templates);
    648     }
    649     catch( TransformerConfigurationException ex )
    650     {
    651       if( m_errorListener != null)
    652       {
    653         try
    654         {
    655           m_errorListener.fatalError( ex );
    656           return null;
    657         }
    658         catch( TransformerConfigurationException ex1 )
    659         {
    660           throw ex1;
    661         }
    662         catch( TransformerException ex1 )
    663         {
    664           throw new TransformerConfigurationException(ex1);
    665         }
    666       }
    667       throw ex;
    668     }
    669   }
    670 
    671   /**
    672    * Get a TransformerHandler object that can process SAX
    673    * ContentHandler events into a Result, based on the transformation
    674    * instructions specified by the argument.
    675    *
    676    * @param src The source of the transformation instructions.
    677    *
    678    * @return TransformerHandler ready to transform SAX events.
    679    *
    680    * @throws TransformerConfigurationException
    681    */
    682   public TransformerHandler newTransformerHandler(Source src)
    683           throws TransformerConfigurationException
    684   {
    685 
    686     Templates templates = newTemplates(src);
    687     if( templates==null ) return null;
    688 
    689     return newTransformerHandler(templates);
    690   }
    691 
    692   /**
    693    * Get a TransformerHandler object that can process SAX
    694    * ContentHandler events into a Result, based on the Templates argument.
    695    *
    696    * @param templates The source of the transformation instructions.
    697    *
    698    * @return TransformerHandler ready to transform SAX events.
    699    * @throws TransformerConfigurationException
    700    */
    701   public TransformerHandler newTransformerHandler(Templates templates)
    702           throws TransformerConfigurationException
    703   {
    704     try {
    705       TransformerImpl transformer =
    706         (TransformerImpl) templates.newTransformer();
    707       transformer.setURIResolver(m_uriResolver);
    708       TransformerHandler th =
    709         (TransformerHandler) transformer.getInputContentHandler(true);
    710 
    711       return th;
    712     }
    713     catch( TransformerConfigurationException ex )
    714     {
    715       if( m_errorListener != null )
    716       {
    717         try
    718         {
    719           m_errorListener.fatalError( ex );
    720           return null;
    721         }
    722         catch (TransformerConfigurationException ex1 )
    723         {
    724           throw ex1;
    725         }
    726         catch (TransformerException ex1 )
    727         {
    728           throw new TransformerConfigurationException(ex1);
    729         }
    730       }
    731 
    732       throw ex;
    733     }
    734 
    735   }
    736 
    737 //  /** The identity transform string, for support of newTransformerHandler()
    738 //   *  and newTransformer().  */
    739 //  private static final String identityTransform =
    740 //    "<xsl:stylesheet " + "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' "
    741 //    + "version='1.0'>" + "<xsl:template match='/|node()'>"
    742 //    + "<xsl:copy-of select='.'/>" + "</xsl:template>" + "</xsl:stylesheet>";
    743 //
    744 //  /** The identity transform Templates, built from identityTransform,
    745 //   *  for support of newTransformerHandler() and newTransformer().  */
    746 //  private static Templates m_identityTemplate = null;
    747 
    748   /**
    749    * Get a TransformerHandler object that can process SAX
    750    * ContentHandler events into a Result.
    751    *
    752    * @return TransformerHandler ready to transform SAX events.
    753    *
    754    * @throws TransformerConfigurationException
    755    */
    756   public TransformerHandler newTransformerHandler()
    757           throws TransformerConfigurationException
    758   {
    759     return new TransformerIdentityImpl(m_isSecureProcessing);
    760   }
    761 
    762   /**
    763    * Process the source into a Transformer object.  Care must
    764    * be given to know that this object can not be used concurrently
    765    * in multiple threads.
    766    *
    767    * @param source An object that holds a URL, input stream, etc.
    768    *
    769    * @return A Transformer object capable of
    770    * being used for transformation purposes in a single thread.
    771    *
    772    * @throws TransformerConfigurationException May throw this during the parse when it
    773    *            is constructing the Templates object and fails.
    774    */
    775   public Transformer newTransformer(Source source)
    776           throws TransformerConfigurationException
    777   {
    778     try
    779     {
    780       Templates tmpl=newTemplates( source );
    781       /* this can happen if an ErrorListener is present and it doesn't
    782          throw any exception in fatalError.
    783          The spec says: "a Transformer must use this interface
    784          instead of throwing an exception" - the newTemplates() does
    785          that, and returns null.
    786       */
    787       if( tmpl==null ) return null;
    788       Transformer transformer = tmpl.newTransformer();
    789       transformer.setURIResolver(m_uriResolver);
    790       return transformer;
    791     }
    792     catch( TransformerConfigurationException ex )
    793     {
    794       if( m_errorListener != null )
    795       {
    796         try
    797         {
    798           m_errorListener.fatalError( ex );
    799           return null; // TODO: but the API promises to never return null...
    800         }
    801         catch( TransformerConfigurationException ex1 )
    802         {
    803           throw ex1;
    804         }
    805         catch( TransformerException ex1 )
    806         {
    807           throw new TransformerConfigurationException( ex1 );
    808         }
    809       }
    810       throw ex;
    811     }
    812   }
    813 
    814   /**
    815    * Create a new Transformer object that performs a copy
    816    * of the source to the result.
    817    *
    818    * @return A Transformer object capable of
    819    * being used for transformation purposes in a single thread.
    820    *
    821    * @throws TransformerConfigurationException May throw this during
    822    *            the parse when it is constructing the
    823    *            Templates object and it fails.
    824    */
    825   public Transformer newTransformer() throws TransformerConfigurationException
    826   {
    827       return new TransformerIdentityImpl(m_isSecureProcessing);
    828   }
    829 
    830   /**
    831    * Process the source into a Templates object, which is likely
    832    * a compiled representation of the source. This Templates object
    833    * may then be used concurrently across multiple threads.  Creating
    834    * a Templates object allows the TransformerFactory to do detailed
    835    * performance optimization of transformation instructions, without
    836    * penalizing runtime transformation.
    837    *
    838    * @param source An object that holds a URL, input stream, etc.
    839    * @return A Templates object capable of being used for transformation purposes.
    840    *
    841    * @throws TransformerConfigurationException May throw this during the parse when it
    842    *            is constructing the Templates object and fails.
    843    */
    844   public Templates newTemplates(Source source)
    845           throws TransformerConfigurationException
    846   {
    847 
    848     String baseID = source.getSystemId();
    849 
    850     if (null != baseID) {
    851        baseID = SystemIDResolver.getAbsoluteURI(baseID);
    852     }
    853 
    854 
    855     if (source instanceof DOMSource)
    856     {
    857       DOMSource dsource = (DOMSource) source;
    858       Node node = dsource.getNode();
    859 
    860       if (null != node)
    861         return processFromNode(node, baseID);
    862       else
    863       {
    864         String messageStr = XSLMessages.createMessage(
    865           XSLTErrorResources.ER_ILLEGAL_DOMSOURCE_INPUT, null);
    866 
    867         throw new IllegalArgumentException(messageStr);
    868       }
    869     }
    870 
    871     TemplatesHandler builder = newTemplatesHandler();
    872     builder.setSystemId(baseID);
    873 
    874     try
    875     {
    876       InputSource isource = SAXSource.sourceToInputSource(source);
    877       isource.setSystemId(baseID);
    878       XMLReader reader = null;
    879 
    880       if (source instanceof SAXSource)
    881         reader = ((SAXSource) source).getXMLReader();
    882 
    883       if (null == reader)
    884       {
    885 
    886         // Use JAXP1.1 ( if possible )
    887         try
    888         {
    889           javax.xml.parsers.SAXParserFactory factory =
    890             javax.xml.parsers.SAXParserFactory.newInstance();
    891 
    892           factory.setNamespaceAware(true);
    893 
    894           if (m_isSecureProcessing)
    895           {
    896             try
    897             {
    898               factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    899             }
    900             catch (org.xml.sax.SAXException se) {}
    901           }
    902 
    903           javax.xml.parsers.SAXParser jaxpParser = factory.newSAXParser();
    904 
    905           reader = jaxpParser.getXMLReader();
    906         }
    907         catch (javax.xml.parsers.ParserConfigurationException ex)
    908         {
    909           throw new org.xml.sax.SAXException(ex);
    910         }
    911         catch (javax.xml.parsers.FactoryConfigurationError ex1)
    912         {
    913           throw new org.xml.sax.SAXException(ex1.toString());
    914         }
    915         catch (NoSuchMethodError ex2){}
    916         catch (AbstractMethodError ame){}
    917       }
    918 
    919       if (null == reader)
    920         reader = XMLReaderFactory.createXMLReader();
    921 
    922       // If you set the namespaces to true, we'll end up getting double
    923       // xmlns attributes.  Needs to be fixed.  -sb
    924       // reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
    925       reader.setContentHandler(builder);
    926       reader.parse(isource);
    927     }
    928     catch (org.xml.sax.SAXException se)
    929     {
    930       if (m_errorListener != null)
    931       {
    932         try
    933         {
    934           m_errorListener.fatalError(new TransformerException(se));
    935         }
    936         catch (TransformerConfigurationException ex1)
    937         {
    938           throw ex1;
    939         }
    940         catch (TransformerException ex1)
    941         {
    942           throw new TransformerConfigurationException(ex1);
    943         }
    944       }
    945       else
    946       {
    947         throw new TransformerConfigurationException(se.getMessage(), se);
    948       }
    949     }
    950     catch (Exception e)
    951     {
    952       if (m_errorListener != null)
    953       {
    954         try
    955         {
    956           m_errorListener.fatalError(new TransformerException(e));
    957           return null;
    958         }
    959         catch (TransformerConfigurationException ex1)
    960         {
    961           throw ex1;
    962         }
    963         catch (TransformerException ex1)
    964         {
    965           throw new TransformerConfigurationException(ex1);
    966         }
    967       }
    968       else
    969       {
    970         throw new TransformerConfigurationException(e.getMessage(), e);
    971       }
    972     }
    973 
    974     return builder.getTemplates();
    975   }
    976 
    977   /**
    978    * The object that implements the URIResolver interface,
    979    * or null.
    980    */
    981   URIResolver m_uriResolver;
    982 
    983   /**
    984    * Set an object that will be used to resolve URIs used in
    985    * xsl:import, etc.  This will be used as the default for the
    986    * transformation.
    987    * @param resolver An object that implements the URIResolver interface,
    988    * or null.
    989    */
    990   public void setURIResolver(URIResolver resolver)
    991   {
    992     m_uriResolver = resolver;
    993   }
    994 
    995   /**
    996    * Get the object that will be used to resolve URIs used in
    997    * xsl:import, etc.  This will be used as the default for the
    998    * transformation.
    999    *
   1000    * @return The URIResolver that was set with setURIResolver.
   1001    */
   1002   public URIResolver getURIResolver()
   1003   {
   1004     return m_uriResolver;
   1005   }
   1006 
   1007   /** The error listener.   */
   1008   private ErrorListener m_errorListener = new org.apache.xml.utils.DefaultErrorHandler(false);
   1009 
   1010   /**
   1011    * Get the error listener in effect for the TransformerFactory.
   1012    *
   1013    * @return A non-null reference to an error listener.
   1014    */
   1015   public ErrorListener getErrorListener()
   1016   {
   1017     return m_errorListener;
   1018   }
   1019 
   1020   /**
   1021    * Set an error listener for the TransformerFactory.
   1022    *
   1023    * @param listener Must be a non-null reference to an ErrorListener.
   1024    *
   1025    * @throws IllegalArgumentException if the listener argument is null.
   1026    */
   1027   public void setErrorListener(ErrorListener listener)
   1028           throws IllegalArgumentException
   1029   {
   1030 
   1031     if (null == listener)
   1032       throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_ERRORLISTENER, null));
   1033       // "ErrorListener");
   1034 
   1035     m_errorListener = listener;
   1036   }
   1037 
   1038   /**
   1039    * Return the state of the secure processing feature.
   1040    *
   1041    * @return state of the secure processing feature.
   1042    */
   1043   public boolean isSecureProcessing()
   1044   {
   1045     return m_isSecureProcessing;
   1046   }
   1047 }
   1048