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         // Need to set options!
    339         reader.setContentHandler(handler);
    340         reader.parse(isource);
    341       }
    342     }
    343     catch (StopParseException spe)
    344     {
    345 
    346       // OK, good.
    347     }
    348     catch (org.xml.sax.SAXException se)
    349     {
    350       throw new TransformerConfigurationException(
    351         "getAssociatedStylesheets failed", se);
    352     }
    353     catch (IOException ioe)
    354     {
    355       throw new TransformerConfigurationException(
    356         "getAssociatedStylesheets failed", ioe);
    357     }
    358 
    359     return handler.getAssociatedStylesheet();
    360   }
    361 
    362   /**
    363    * Create a new Transformer object that performs a copy
    364    * of the source to the result.
    365    *
    366    * @return A Transformer object that may be used to perform a transformation
    367    * in a single thread, never null.
    368    *
    369    * @throws TransformerConfigurationException May throw this during
    370    *            the parse when it is constructing the
    371    *            Templates object and fails.
    372    */
    373   public TemplatesHandler newTemplatesHandler()
    374           throws TransformerConfigurationException
    375   {
    376     return new StylesheetHandler(this);
    377   }
    378 
    379   /**
    380    * <p>Set a feature for this <code>TransformerFactory</code> and <code>Transformer</code>s
    381    * or <code>Template</code>s created by this factory.</p>
    382    *
    383    * <p>
    384    * Feature names are fully qualified {@link java.net.URI}s.
    385    * Implementations may define their own features.
    386    * An {@link TransformerConfigurationException} is thrown if this <code>TransformerFactory</code> or the
    387    * <code>Transformer</code>s or <code>Template</code>s it creates cannot support the feature.
    388    * It is possible for an <code>TransformerFactory</code> to expose a feature value but be unable to change its state.
    389    * </p>
    390    *
    391    * <p>See {@link javax.xml.transform.TransformerFactory} for full documentation of specific features.</p>
    392    *
    393    * @param name Feature name.
    394    * @param value Is feature state <code>true</code> or <code>false</code>.
    395    *
    396    * @throws TransformerConfigurationException if this <code>TransformerFactory</code>
    397    *   or the <code>Transformer</code>s or <code>Template</code>s it creates cannot support this feature.
    398    * @throws NullPointerException If the <code>name</code> parameter is null.
    399    */
    400   public void setFeature(String name, boolean value)
    401 	  throws TransformerConfigurationException {
    402 
    403   	// feature name cannot be null
    404   	if (name == null) {
    405   	    throw new NullPointerException(
    406                   XSLMessages.createMessage(
    407                       XSLTErrorResources.ER_SET_FEATURE_NULL_NAME, null));
    408   	}
    409 
    410   	// secure processing?
    411   	if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
    412   	    m_isSecureProcessing = value;
    413   	}
    414   	// This implementation does not support the setting of a feature other than
    415   	// the secure processing feature.
    416   	else
    417     {
    418       throw new TransformerConfigurationException(
    419           XSLMessages.createMessage(
    420             XSLTErrorResources.ER_UNSUPPORTED_FEATURE,
    421             new Object[] {name}));
    422     }
    423   }
    424 
    425   /**
    426    * Look up the value of a feature.
    427    * <p>The feature name is any fully-qualified URI.  It is
    428    * possible for an TransformerFactory to recognize a feature name but
    429    * to be unable to return its value; this is especially true
    430    * in the case of an adapter for a SAX1 Parser, which has
    431    * no way of knowing whether the underlying parser is
    432    * validating, for example.</p>
    433    *
    434    * @param name The feature name, which is a fully-qualified URI.
    435    * @return The current state of the feature (true or false).
    436    */
    437   public boolean getFeature(String name) {
    438 
    439     // feature name cannot be null
    440     if (name == null)
    441     {
    442     	throw new NullPointerException(
    443             XSLMessages.createMessage(
    444             XSLTErrorResources.ER_GET_FEATURE_NULL_NAME, null));
    445     }
    446 
    447     // Try first with identity comparison, which
    448     // will be faster.
    449     if ((DOMResult.FEATURE == name) || (DOMSource.FEATURE == name)
    450             || (SAXResult.FEATURE == name) || (SAXSource.FEATURE == name)
    451             || (StreamResult.FEATURE == name)
    452             || (StreamSource.FEATURE == name)
    453             || (SAXTransformerFactory.FEATURE == name)
    454             || (SAXTransformerFactory.FEATURE_XMLFILTER == name))
    455       return true;
    456     else if ((DOMResult.FEATURE.equals(name))
    457              || (DOMSource.FEATURE.equals(name))
    458              || (SAXResult.FEATURE.equals(name))
    459              || (SAXSource.FEATURE.equals(name))
    460              || (StreamResult.FEATURE.equals(name))
    461              || (StreamSource.FEATURE.equals(name))
    462              || (SAXTransformerFactory.FEATURE.equals(name))
    463              || (SAXTransformerFactory.FEATURE_XMLFILTER.equals(name)))
    464       return true;
    465     // secure processing?
    466     else if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING))
    467       return m_isSecureProcessing;
    468     else
    469       // unknown feature
    470       return false;
    471   }
    472 
    473   /**
    474    * Flag set by FEATURE_OPTIMIZE.
    475    * This feature specifies whether to Optimize stylesheet processing. By
    476    * default it is set to true.
    477    */
    478   private boolean m_optimize = true;
    479 
    480   /** Flag set by FEATURE_SOURCE_LOCATION.
    481    * This feature specifies whether the transformation phase should
    482    * keep track of line and column numbers for the input source
    483    * document. Note that this works only when that
    484    * information is available from the source -- in other words, if you
    485    * pass in a DOM, there's little we can do for you.
    486    *
    487    * The default is false. Setting it true may significantly
    488    * increase storage cost per node.
    489    */
    490   private boolean m_source_location = false;
    491 
    492   /**
    493    * Flag set by FEATURE_INCREMENTAL.
    494    * This feature specifies whether to produce output incrementally, rather than
    495    * waiting to finish parsing the input before generating any output. By
    496    * default this attribute is set to false.
    497    */
    498   private boolean m_incremental = false;
    499 
    500   /**
    501    * Allows the user to set specific attributes on the underlying
    502    * implementation.
    503    *
    504    * @param name The name of the attribute.
    505    * @param value The value of the attribute; Boolean or String="true"|"false"
    506    *
    507    * @throws IllegalArgumentException thrown if the underlying
    508    * implementation doesn't recognize the attribute.
    509    */
    510   public void setAttribute(String name, Object value)
    511           throws IllegalArgumentException
    512   {
    513     if (name.equals(FEATURE_INCREMENTAL))
    514     {
    515       if(value instanceof Boolean)
    516       {
    517         // Accept a Boolean object..
    518         m_incremental = ((Boolean)value).booleanValue();
    519       }
    520       else if(value instanceof String)
    521       {
    522         // .. or a String object
    523         m_incremental = (new Boolean((String)value)).booleanValue();
    524       }
    525       else
    526       {
    527         // Give a more meaningful error message
    528         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
    529       }
    530 	}
    531     else if (name.equals(FEATURE_OPTIMIZE))
    532     {
    533       if(value instanceof Boolean)
    534       {
    535         // Accept a Boolean object..
    536         m_optimize = ((Boolean)value).booleanValue();
    537       }
    538       else if(value instanceof String)
    539       {
    540         // .. or a String object
    541         m_optimize = (new Boolean((String)value)).booleanValue();
    542       }
    543       else
    544       {
    545         // Give a more meaningful error message
    546         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
    547       }
    548     }
    549 
    550     // Custom Xalan feature: annotate DTM with SAX source locator fields.
    551     // This gets used during SAX2DTM instantiation.
    552     //
    553     // %REVIEW% Should the name of this field really be in XalanProperties?
    554     // %REVIEW% I hate that it's a global static, but didn't want to change APIs yet.
    555     else if(name.equals(FEATURE_SOURCE_LOCATION))
    556     {
    557       if(value instanceof Boolean)
    558       {
    559         // Accept a Boolean object..
    560         m_source_location = ((Boolean)value).booleanValue();
    561       }
    562       else if(value instanceof String)
    563       {
    564         // .. or a String object
    565         m_source_location = (new Boolean((String)value)).booleanValue();
    566       }
    567       else
    568       {
    569         // Give a more meaningful error message
    570         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
    571       }
    572     }
    573 
    574     else
    575     {
    576       throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_SUPPORTED, new Object[]{name})); //name + "not supported");
    577     }
    578   }
    579 
    580   /**
    581    * Allows the user to retrieve specific attributes on the underlying
    582    * implementation.
    583    *
    584    * @param name The name of the attribute.
    585    * @return value The value of the attribute.
    586    *
    587    * @throws IllegalArgumentException thrown if the underlying
    588    * implementation doesn't recognize the attribute.
    589    */
    590   public Object getAttribute(String name) throws IllegalArgumentException
    591   {
    592     if (name.equals(FEATURE_INCREMENTAL))
    593     {
    594       return new Boolean(m_incremental);
    595     }
    596     else if (name.equals(FEATURE_OPTIMIZE))
    597     {
    598       return new Boolean(m_optimize);
    599     }
    600     else if (name.equals(FEATURE_SOURCE_LOCATION))
    601     {
    602       return new Boolean(m_source_location);
    603     }
    604     else
    605       throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_ATTRIB_VALUE_NOT_RECOGNIZED, new Object[]{name})); //name + " attribute not recognized");
    606   }
    607 
    608   /**
    609    * Create an XMLFilter that uses the given source as the
    610    * transformation instructions.
    611    *
    612    * @param src The source of the transformation instructions.
    613    *
    614    * @return An XMLFilter object, or null if this feature is not supported.
    615    *
    616    * @throws TransformerConfigurationException
    617    */
    618   public XMLFilter newXMLFilter(Source src)
    619           throws TransformerConfigurationException
    620   {
    621 
    622     Templates templates = newTemplates(src);
    623     if( templates==null ) return null;
    624 
    625     return newXMLFilter(templates);
    626   }
    627 
    628   /**
    629    * Create an XMLFilter that uses the given source as the
    630    * transformation instructions.
    631    *
    632    * @param templates non-null reference to Templates object.
    633    *
    634    * @return An XMLFilter object, or null if this feature is not supported.
    635    *
    636    * @throws TransformerConfigurationException
    637    */
    638   public XMLFilter newXMLFilter(Templates templates)
    639           throws TransformerConfigurationException
    640   {
    641     try
    642     {
    643       return new TrAXFilter(templates);
    644     }
    645     catch( TransformerConfigurationException ex )
    646     {
    647       if( m_errorListener != null)
    648       {
    649         try
    650         {
    651           m_errorListener.fatalError( ex );
    652           return null;
    653         }
    654         catch( TransformerConfigurationException ex1 )
    655         {
    656           throw ex1;
    657         }
    658         catch( TransformerException ex1 )
    659         {
    660           throw new TransformerConfigurationException(ex1);
    661         }
    662       }
    663       throw ex;
    664     }
    665   }
    666 
    667   /**
    668    * Get a TransformerHandler object that can process SAX
    669    * ContentHandler events into a Result, based on the transformation
    670    * instructions specified by the argument.
    671    *
    672    * @param src The source of the transformation instructions.
    673    *
    674    * @return TransformerHandler ready to transform SAX events.
    675    *
    676    * @throws TransformerConfigurationException
    677    */
    678   public TransformerHandler newTransformerHandler(Source src)
    679           throws TransformerConfigurationException
    680   {
    681 
    682     Templates templates = newTemplates(src);
    683     if( templates==null ) return null;
    684 
    685     return newTransformerHandler(templates);
    686   }
    687 
    688   /**
    689    * Get a TransformerHandler object that can process SAX
    690    * ContentHandler events into a Result, based on the Templates argument.
    691    *
    692    * @param templates The source of the transformation instructions.
    693    *
    694    * @return TransformerHandler ready to transform SAX events.
    695    * @throws TransformerConfigurationException
    696    */
    697   public TransformerHandler newTransformerHandler(Templates templates)
    698           throws TransformerConfigurationException
    699   {
    700     try {
    701       TransformerImpl transformer =
    702         (TransformerImpl) templates.newTransformer();
    703       transformer.setURIResolver(m_uriResolver);
    704       TransformerHandler th =
    705         (TransformerHandler) transformer.getInputContentHandler(true);
    706 
    707       return th;
    708     }
    709     catch( TransformerConfigurationException ex )
    710     {
    711       if( m_errorListener != null )
    712       {
    713         try
    714         {
    715           m_errorListener.fatalError( ex );
    716           return null;
    717         }
    718         catch (TransformerConfigurationException ex1 )
    719         {
    720           throw ex1;
    721         }
    722         catch (TransformerException ex1 )
    723         {
    724           throw new TransformerConfigurationException(ex1);
    725         }
    726       }
    727 
    728       throw ex;
    729     }
    730 
    731   }
    732 
    733 //  /** The identity transform string, for support of newTransformerHandler()
    734 //   *  and newTransformer().  */
    735 //  private static final String identityTransform =
    736 //    "<xsl:stylesheet " + "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' "
    737 //    + "version='1.0'>" + "<xsl:template match='/|node()'>"
    738 //    + "<xsl:copy-of select='.'/>" + "</xsl:template>" + "</xsl:stylesheet>";
    739 //
    740 //  /** The identity transform Templates, built from identityTransform,
    741 //   *  for support of newTransformerHandler() and newTransformer().  */
    742 //  private static Templates m_identityTemplate = null;
    743 
    744   /**
    745    * Get a TransformerHandler object that can process SAX
    746    * ContentHandler events into a Result.
    747    *
    748    * @return TransformerHandler ready to transform SAX events.
    749    *
    750    * @throws TransformerConfigurationException
    751    */
    752   public TransformerHandler newTransformerHandler()
    753           throws TransformerConfigurationException
    754   {
    755     return new TransformerIdentityImpl(m_isSecureProcessing);
    756   }
    757 
    758   /**
    759    * Process the source into a Transformer object.  Care must
    760    * be given to know that this object can not be used concurrently
    761    * in multiple threads.
    762    *
    763    * @param source An object that holds a URL, input stream, etc.
    764    *
    765    * @return A Transformer object capable of
    766    * being used for transformation purposes in a single thread.
    767    *
    768    * @throws TransformerConfigurationException May throw this during the parse when it
    769    *            is constructing the Templates object and fails.
    770    */
    771   public Transformer newTransformer(Source source)
    772           throws TransformerConfigurationException
    773   {
    774     try
    775     {
    776       Templates tmpl=newTemplates( source );
    777       /* this can happen if an ErrorListener is present and it doesn't
    778          throw any exception in fatalError.
    779          The spec says: "a Transformer must use this interface
    780          instead of throwing an exception" - the newTemplates() does
    781          that, and returns null.
    782       */
    783       if( tmpl==null ) return null;
    784       Transformer transformer = tmpl.newTransformer();
    785       transformer.setURIResolver(m_uriResolver);
    786       return transformer;
    787     }
    788     catch( TransformerConfigurationException ex )
    789     {
    790       if( m_errorListener != null )
    791       {
    792         try
    793         {
    794           m_errorListener.fatalError( ex );
    795           return null; // TODO: but the API promises to never return null...
    796         }
    797         catch( TransformerConfigurationException ex1 )
    798         {
    799           throw ex1;
    800         }
    801         catch( TransformerException ex1 )
    802         {
    803           throw new TransformerConfigurationException( ex1 );
    804         }
    805       }
    806       throw ex;
    807     }
    808   }
    809 
    810   /**
    811    * Create a new Transformer object that performs a copy
    812    * of the source to the result.
    813    *
    814    * @return A Transformer object capable of
    815    * being used for transformation purposes in a single thread.
    816    *
    817    * @throws TransformerConfigurationException May throw this during
    818    *            the parse when it is constructing the
    819    *            Templates object and it fails.
    820    */
    821   public Transformer newTransformer() throws TransformerConfigurationException
    822   {
    823       return new TransformerIdentityImpl(m_isSecureProcessing);
    824   }
    825 
    826   /**
    827    * Process the source into a Templates object, which is likely
    828    * a compiled representation of the source. This Templates object
    829    * may then be used concurrently across multiple threads.  Creating
    830    * a Templates object allows the TransformerFactory to do detailed
    831    * performance optimization of transformation instructions, without
    832    * penalizing runtime transformation.
    833    *
    834    * @param source An object that holds a URL, input stream, etc.
    835    * @return A Templates object capable of being used for transformation purposes.
    836    *
    837    * @throws TransformerConfigurationException May throw this during the parse when it
    838    *            is constructing the Templates object and fails.
    839    */
    840   public Templates newTemplates(Source source)
    841           throws TransformerConfigurationException
    842   {
    843 
    844     String baseID = source.getSystemId();
    845 
    846     if (null != baseID) {
    847        baseID = SystemIDResolver.getAbsoluteURI(baseID);
    848     }
    849 
    850 
    851     if (source instanceof DOMSource)
    852     {
    853       DOMSource dsource = (DOMSource) source;
    854       Node node = dsource.getNode();
    855 
    856       if (null != node)
    857         return processFromNode(node, baseID);
    858       else
    859       {
    860         String messageStr = XSLMessages.createMessage(
    861           XSLTErrorResources.ER_ILLEGAL_DOMSOURCE_INPUT, null);
    862 
    863         throw new IllegalArgumentException(messageStr);
    864       }
    865     }
    866 
    867     TemplatesHandler builder = newTemplatesHandler();
    868     builder.setSystemId(baseID);
    869 
    870     try
    871     {
    872       InputSource isource = SAXSource.sourceToInputSource(source);
    873       isource.setSystemId(baseID);
    874       XMLReader reader = null;
    875 
    876       if (source instanceof SAXSource)
    877         reader = ((SAXSource) source).getXMLReader();
    878 
    879       if (null == reader)
    880       {
    881 
    882         // Use JAXP1.1 ( if possible )
    883         try
    884         {
    885           javax.xml.parsers.SAXParserFactory factory =
    886             javax.xml.parsers.SAXParserFactory.newInstance();
    887 
    888           factory.setNamespaceAware(true);
    889 
    890           if (m_isSecureProcessing)
    891           {
    892             try
    893             {
    894               factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    895             }
    896             catch (org.xml.sax.SAXException se) {}
    897           }
    898 
    899           javax.xml.parsers.SAXParser jaxpParser = factory.newSAXParser();
    900 
    901           reader = jaxpParser.getXMLReader();
    902         }
    903         catch (javax.xml.parsers.ParserConfigurationException ex)
    904         {
    905           throw new org.xml.sax.SAXException(ex);
    906         }
    907         catch (javax.xml.parsers.FactoryConfigurationError ex1)
    908         {
    909           throw new org.xml.sax.SAXException(ex1.toString());
    910         }
    911         catch (NoSuchMethodError ex2){}
    912         catch (AbstractMethodError ame){}
    913       }
    914 
    915       if (null == reader)
    916         reader = XMLReaderFactory.createXMLReader();
    917 
    918       // If you set the namespaces to true, we'll end up getting double
    919       // xmlns attributes.  Needs to be fixed.  -sb
    920       // reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
    921       reader.setContentHandler(builder);
    922       reader.parse(isource);
    923     }
    924     catch (org.xml.sax.SAXException se)
    925     {
    926       if (m_errorListener != null)
    927       {
    928         try
    929         {
    930           m_errorListener.fatalError(new TransformerException(se));
    931         }
    932         catch (TransformerConfigurationException ex1)
    933         {
    934           throw ex1;
    935         }
    936         catch (TransformerException ex1)
    937         {
    938           throw new TransformerConfigurationException(ex1);
    939         }
    940       }
    941       else
    942       {
    943         throw new TransformerConfigurationException(se.getMessage(), se);
    944       }
    945     }
    946     catch (Exception e)
    947     {
    948       if (m_errorListener != null)
    949       {
    950         try
    951         {
    952           m_errorListener.fatalError(new TransformerException(e));
    953           return null;
    954         }
    955         catch (TransformerConfigurationException ex1)
    956         {
    957           throw ex1;
    958         }
    959         catch (TransformerException ex1)
    960         {
    961           throw new TransformerConfigurationException(ex1);
    962         }
    963       }
    964       else
    965       {
    966         throw new TransformerConfigurationException(e.getMessage(), e);
    967       }
    968     }
    969 
    970     return builder.getTemplates();
    971   }
    972 
    973   /**
    974    * The object that implements the URIResolver interface,
    975    * or null.
    976    */
    977   URIResolver m_uriResolver;
    978 
    979   /**
    980    * Set an object that will be used to resolve URIs used in
    981    * xsl:import, etc.  This will be used as the default for the
    982    * transformation.
    983    * @param resolver An object that implements the URIResolver interface,
    984    * or null.
    985    */
    986   public void setURIResolver(URIResolver resolver)
    987   {
    988     m_uriResolver = resolver;
    989   }
    990 
    991   /**
    992    * Get the object that will be used to resolve URIs used in
    993    * xsl:import, etc.  This will be used as the default for the
    994    * transformation.
    995    *
    996    * @return The URIResolver that was set with setURIResolver.
    997    */
    998   public URIResolver getURIResolver()
    999   {
   1000     return m_uriResolver;
   1001   }
   1002 
   1003   /** The error listener.   */
   1004   private ErrorListener m_errorListener = new org.apache.xml.utils.DefaultErrorHandler(false);
   1005 
   1006   /**
   1007    * Get the error listener in effect for the TransformerFactory.
   1008    *
   1009    * @return A non-null reference to an error listener.
   1010    */
   1011   public ErrorListener getErrorListener()
   1012   {
   1013     return m_errorListener;
   1014   }
   1015 
   1016   /**
   1017    * Set an error listener for the TransformerFactory.
   1018    *
   1019    * @param listener Must be a non-null reference to an ErrorListener.
   1020    *
   1021    * @throws IllegalArgumentException if the listener argument is null.
   1022    */
   1023   public void setErrorListener(ErrorListener listener)
   1024           throws IllegalArgumentException
   1025   {
   1026 
   1027     if (null == listener)
   1028       throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_ERRORLISTENER, null));
   1029       // "ErrorListener");
   1030 
   1031     m_errorListener = listener;
   1032   }
   1033 
   1034   /**
   1035    * Return the state of the secure processing feature.
   1036    *
   1037    * @return state of the secure processing feature.
   1038    */
   1039   public boolean isSecureProcessing()
   1040   {
   1041     return m_isSecureProcessing;
   1042   }
   1043 }
   1044