OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / org / apache / xalan / processor / TransformerFactoryImpl.java
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 }