KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xalan > internal > xsltc > trax > TransformerImpl


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: TransformerImpl.java,v 1.1.2.1 2006/09/19 01:07:41 jeffsuttor Exp $
18  */

19
20 package com.sun.org.apache.xalan.internal.xsltc.trax;
21
22 import java.io.File JavaDoc;
23 import java.io.FileOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import java.io.Reader JavaDoc;
28 import java.io.Writer JavaDoc;
29 import java.net.URI JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.net.URLConnection JavaDoc;
32 import java.net.UnknownServiceException JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.Properties JavaDoc;
35 import java.util.StringTokenizer JavaDoc;
36 import java.util.Vector JavaDoc;
37 import java.lang.reflect.Constructor JavaDoc;
38
39 import javax.xml.parsers.DocumentBuilder JavaDoc;
40 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
41 import javax.xml.parsers.ParserConfigurationException JavaDoc;
42 import javax.xml.transform.ErrorListener JavaDoc;
43 import javax.xml.transform.OutputKeys JavaDoc;
44 import javax.xml.transform.Result JavaDoc;
45 import javax.xml.transform.Source JavaDoc;
46 import javax.xml.transform.Transformer JavaDoc;
47 import javax.xml.transform.TransformerException JavaDoc;
48 import javax.xml.transform.URIResolver JavaDoc;
49 import javax.xml.transform.dom.DOMResult JavaDoc;
50 import javax.xml.transform.dom.DOMSource JavaDoc;
51 import javax.xml.transform.sax.SAXResult JavaDoc;
52 import javax.xml.transform.sax.SAXSource JavaDoc;
53 import javax.xml.transform.stream.StreamResult JavaDoc;
54 import javax.xml.transform.stream.StreamSource JavaDoc;
55
56 import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
57
58 import com.sun.org.apache.xalan.internal.xsltc.DOM;
59 import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
60 import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
61 import com.sun.org.apache.xalan.internal.xsltc.StripFilter;
62 import com.sun.org.apache.xalan.internal.xsltc.Translet;
63 import com.sun.org.apache.xalan.internal.xsltc.TransletException;
64 import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory;
65 import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
66 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
67 import com.sun.org.apache.xalan.internal.xsltc.dom.DOMWSFilter;
68 import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl;
69 import com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager;
70 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
71 import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
72 import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
73
74 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
75 import com.sun.org.apache.xml.internal.utils.XMLReaderManager;
76
77 import org.xml.sax.ContentHandler JavaDoc;
78 import org.xml.sax.InputSource JavaDoc;
79 import org.xml.sax.SAXException JavaDoc;
80 import org.xml.sax.XMLReader JavaDoc;
81 import org.xml.sax.ext.LexicalHandler JavaDoc;
82
83 /**
84  * @author Morten Jorgensen
85  * @author G. Todd Miller
86  * @author Santiago Pericas-Geertsen
87  */

88 public final class TransformerImpl extends Transformer JavaDoc
89     implements DOMCache, ErrorListener JavaDoc
90 {
91     private final static String JavaDoc EMPTY_STRING = "";
92     private final static String JavaDoc NO_STRING = "no";
93     private final static String JavaDoc YES_STRING = "yes";
94     private final static String JavaDoc XML_STRING = "xml";
95
96     private final static String JavaDoc LEXICAL_HANDLER_PROPERTY =
97     "http://xml.org/sax/properties/lexical-handler";
98     private static final String JavaDoc NAMESPACE_FEATURE =
99     "http://xml.org/sax/features/namespaces";
100     private static final String JavaDoc NAMESPACE_PREFIXES_FEATURE =
101     "http://xml.org/sax/features/namespace-prefixes";
102     
103     /**
104      * A reference to the translet or null if the identity transform.
105      */

106     private AbstractTranslet _translet = null;
107
108     /**
109      * The output method of this transformation.
110      */

111     private String JavaDoc _method = null;
112
113     /**
114      * The output encoding of this transformation.
115      */

116     private String JavaDoc _encoding = null;
117
118     /**
119      * The systemId set in input source.
120      */

121     private String JavaDoc _sourceSystemId = null;
122
123     /**
124      * An error listener for runtime errors.
125      */

126     private ErrorListener JavaDoc _errorListener = this;
127
128     /**
129      * A reference to a URI resolver for calls to document().
130      */

131     private URIResolver JavaDoc _uriResolver = null;
132
133     /**
134      * Output properties of this transformer instance.
135      */

136     private Properties JavaDoc _properties, _propertiesClone;
137
138     /**
139      * A reference to an output handler factory.
140      */

141     private TransletOutputHandlerFactory _tohFactory = null;
142
143     /**
144      * A reference to a internal DOM represenation of the input.
145      */

146     private DOM _dom = null;
147
148     /**
149      * Number of indent spaces to add when indentation is on.
150      */

151     private int _indentNumber;
152
153     /**
154      * A reference to the transformer factory that this templates
155      * object belongs to.
156      */

157     private TransformerFactoryImpl _tfactory = null;
158
159     /**
160      * A reference to the XSLTCDTMManager which is used to build the DOM/DTM
161      * for this transformer.
162      */

163     private XSLTCDTMManager _dtmManager = null;
164
165     /**
166      * A reference to an object that creates and caches XMLReader objects.
167      */

168     private XMLReaderManager _readerManager = XMLReaderManager.getInstance();
169     
170     /**
171      * A flag indicating whether we use incremental building of the DTM.
172      */

173     //private boolean _isIncremental = false;
174

175     /**
176      * A flag indicating whether this transformer implements the identity
177      * transform.
178      */

179     private boolean _isIdentity = false;
180
181     /**
182      * State of the secure processing feature.
183      */

184     private boolean _isSecureProcessing = false;
185
186     /**
187      * A hashtable to store parameters for the identity transform. These
188      * are not needed during the transformation, but we must keep track of
189      * them to be fully complaint with the JAXP API.
190      */

191     private Hashtable _parameters = null;
192
193     /**
194      * This class wraps an ErrorListener into a MessageHandler in order to
195      * capture messages reported via xsl:message.
196      */

197     static class MessageHandler
198            extends com.sun.org.apache.xalan.internal.xsltc.runtime.MessageHandler
199     {
200     private ErrorListener JavaDoc _errorListener;
201      
202     public MessageHandler(ErrorListener JavaDoc errorListener) {
203         _errorListener = errorListener;
204     }
205      
206     public void displayMessage(String JavaDoc msg) {
207         if(_errorListener == null) {
208         System.err.println(msg);
209         }
210         else {
211         try {
212             _errorListener.warning(new TransformerException JavaDoc(msg));
213         }
214         catch (TransformerException JavaDoc e) {
215             // ignored
216
}
217         }
218     }
219     }
220
221     protected TransformerImpl(Properties JavaDoc outputProperties, int indentNumber,
222     TransformerFactoryImpl tfactory)
223     {
224     this(null, outputProperties, indentNumber, tfactory);
225     _isIdentity = true;
226     // _properties.put(OutputKeys.METHOD, "xml");
227
}
228
229     protected TransformerImpl(Translet translet, Properties JavaDoc outputProperties,
230     int indentNumber, TransformerFactoryImpl tfactory)
231     {
232     _translet = (AbstractTranslet) translet;
233     _properties = createOutputProperties(outputProperties);
234     _propertiesClone = (Properties JavaDoc) _properties.clone();
235     _indentNumber = indentNumber;
236     _tfactory = tfactory;
237     //_isIncremental = tfactory._incremental;
238
}
239
240     /**
241      * Return the state of the secure processing feature.
242      */

243     public boolean isSecureProcessing() {
244         return _isSecureProcessing;
245     }
246     
247     /**
248      * Set the state of the secure processing feature.
249      */

250     public void setSecureProcessing(boolean flag) {
251         _isSecureProcessing = flag;
252     }
253
254     /**
255      * Returns the translet wrapped inside this Transformer or
256      * null if this is the identity transform.
257      */

258     protected AbstractTranslet getTranslet() {
259     return _translet;
260     }
261
262     public boolean isIdentity() {
263     return _isIdentity;
264     }
265
266     /**
267      * Implements JAXP's Transformer.transform()
268      *
269      * @param source Contains the input XML document
270      * @param result Will contain the output from the transformation
271      * @throws TransformerException
272      */

273     public void transform(Source JavaDoc source, Result JavaDoc result)
274     throws TransformerException JavaDoc
275     {
276     if (!_isIdentity) {
277         if (_translet == null) {
278         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_TRANSLET_ERR);
279         throw new TransformerException JavaDoc(err.toString());
280         }
281         // Pass output properties to the translet
282
transferOutputProperties(_translet);
283     }
284         
285     final SerializationHandler toHandler = getOutputHandler(result);
286     if (toHandler == null) {
287         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_HANDLER_ERR);
288         throw new TransformerException JavaDoc(err.toString());
289     }
290
291     if (_uriResolver != null && !_isIdentity) {
292         _translet.setDOMCache(this);
293     }
294
295     // Pass output properties to handler if identity
296
if (_isIdentity) {
297         transferOutputProperties(toHandler);
298     }
299
300     transform(source, toHandler, _encoding);
301
302     if (result instanceof DOMResult JavaDoc) {
303         ((DOMResult JavaDoc)result).setNode(_tohFactory.getNode());
304     }
305     }
306
307     /**
308      * Create an output handler for the transformation output based on
309      * the type and contents of the TrAX Result object passed to the
310      * transform() method.
311      */

312     public SerializationHandler getOutputHandler(Result JavaDoc result)
313     throws TransformerException JavaDoc
314     {
315     // Get output method using get() to ignore defaults
316
_method = (String JavaDoc) _properties.get(OutputKeys.METHOD);
317
318     // Get encoding using getProperty() to use defaults
319
_encoding = (String JavaDoc) _properties.getProperty(OutputKeys.ENCODING);
320
321     _tohFactory = TransletOutputHandlerFactory.newInstance();
322     _tohFactory.setEncoding(_encoding);
323     if (_method != null) {
324         _tohFactory.setOutputMethod(_method);
325     }
326
327     // Set indentation number in the factory
328
if (_indentNumber >= 0) {
329         _tohFactory.setIndentNumber(_indentNumber);
330     }
331
332     // Return the content handler for this Result object
333
try {
334         // Result object could be SAXResult, DOMResult, or StreamResult
335
if (result instanceof SAXResult JavaDoc) {
336                 final SAXResult JavaDoc target = (SAXResult JavaDoc)result;
337                 final ContentHandler JavaDoc handler = target.getHandler();
338
339         _tohFactory.setHandler(handler);
340
341                 /**
342                  * Fix for bug 24414
343                  * If the lexicalHandler is set then we need to get that
344                  * for obtaining the lexical information
345                  */

346                 LexicalHandler JavaDoc lexicalHandler = target.getLexicalHandler();
347
348                 if (lexicalHandler != null ) {
349             _tohFactory.setLexicalHandler(lexicalHandler);
350         }
351
352         _tohFactory.setOutputType(TransletOutputHandlerFactory.SAX);
353         return _tohFactory.getSerializationHandler();
354             }
355         else if (result instanceof DOMResult JavaDoc) {
356         _tohFactory.setNode(((DOMResult JavaDoc) result).getNode());
357         _tohFactory.setOutputType(TransletOutputHandlerFactory.DOM);
358         return _tohFactory.getSerializationHandler();
359             }
360         else if (result instanceof StreamResult JavaDoc) {
361         // Get StreamResult
362
final StreamResult JavaDoc target = (StreamResult JavaDoc) result;
363
364         // StreamResult may have been created with a java.io.File,
365
// java.io.Writer, java.io.OutputStream or just a String
366
// systemId.
367

368         _tohFactory.setOutputType(TransletOutputHandlerFactory.STREAM);
369
370         // try to get a Writer from Result object
371
final Writer JavaDoc writer = target.getWriter();
372         if (writer != null) {
373             _tohFactory.setWriter(writer);
374             return _tohFactory.getSerializationHandler();
375         }
376
377         // or try to get an OutputStream from Result object
378
final OutputStream JavaDoc ostream = target.getOutputStream();
379         if (ostream != null) {
380             _tohFactory.setOutputStream(ostream);
381             return _tohFactory.getSerializationHandler();
382         }
383
384         // or try to get just a systemId string from Result object
385
String JavaDoc systemId = result.getSystemId();
386         if (systemId == null) {
387             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_RESULT_ERR);
388                     throw new TransformerException JavaDoc(err.toString());
389         }
390
391         // System Id may be in one of several forms, (1) a uri
392
// that starts with 'file:', (2) uri that starts with 'http:'
393
// or (3) just a filename on the local system.
394
URL JavaDoc url = null;
395
396         if (systemId.startsWith("file:")) {
397             // if StreamResult(File) or setSystemID(File) was used,
398
// the systemId will be URI encoded as a result of File.toURI(),
399
// it must be decoded for use by URL
400
try{
401                             Class JavaDoc clazz = ObjectFactory.findProviderClass("java.net.URI", ObjectFactory.findClassLoader(), true);
402                             Constructor JavaDoc construct = clazz.getConstructor(new Class JavaDoc[] {java.lang.String JavaDoc.class} );
403                             URI JavaDoc uri = (URI JavaDoc) construct.newInstance(new Object JavaDoc[]{systemId}) ;
404                             systemId = "file:";
405                             
406                             String JavaDoc host = uri.getHost(); // decoded String
407
String JavaDoc path = uri.getPath(); //decoded String
408
if (path == null) {
409                              path = "";
410                             }
411                             
412                             // if host (URI authority) then file:// + host + path
413
// else just path (may be absolute or relative)
414
if (host != null) {
415                              systemId += "//" + host + path;
416                             } else {
417                              systemId += path;
418                             }
419                         }
420                         catch(ClassNotFoundException JavaDoc e){
421                             // running on J2SE 1.3 which doesn't have URI Class so OK to ignore
422
//ClassNotFoundException.
423
}
424                         catch (Exception JavaDoc exception) {
425                     // URI exception which means nothing can be done so OK to ignore
426
}
427                         
428                     url = new URL JavaDoc(systemId);
429                     
430             _tohFactory.setOutputStream(
431                 new FileOutputStream JavaDoc(url.getFile()));
432             return _tohFactory.getSerializationHandler();
433                 }
434                 else if (systemId.startsWith("http:")) {
435                     url = new URL JavaDoc(systemId);
436                     final URLConnection JavaDoc connection = url.openConnection();
437             _tohFactory.setOutputStream(connection.getOutputStream());
438             return _tohFactory.getSerializationHandler();
439                 }
440                 else {
441                     // system id is just a filename
442
url = new File JavaDoc(systemId).toURL();
443             _tohFactory.setOutputStream(
444                 new FileOutputStream JavaDoc(url.getFile()));
445             return _tohFactory.getSerializationHandler();
446                 }
447         }
448     }
449         // If we cannot write to the location specified by the SystemId
450
catch (UnknownServiceException JavaDoc e) {
451             throw new TransformerException JavaDoc(e);
452         }
453         catch (ParserConfigurationException JavaDoc e) {
454             throw new TransformerException JavaDoc(e);
455         }
456         // If we cannot create the file specified by the SystemId
457
catch (IOException JavaDoc e) {
458             throw new TransformerException JavaDoc(e);
459         }
460     return null;
461     }
462
463     /**
464      * Set the internal DOM that will be used for the next transformation
465      */

466     protected void setDOM(DOM dom) {
467     _dom = dom;
468     }
469
470     /**
471      * Builds an internal DOM from a TrAX Source object
472      */

473     private DOM getDOM(Source JavaDoc source) throws TransformerException JavaDoc {
474         try {
475             DOM dom = null;
476
477             if (source != null) {
478                 DTMWSFilter wsfilter;
479                 if (_translet != null && _translet instanceof StripFilter) {
480                     wsfilter = new DOMWSFilter(_translet);
481                  } else {
482                     wsfilter = null;
483                  }
484             
485                  boolean hasIdCall = (_translet != null) ? _translet.hasIdCall()
486                                                          : false;
487
488                  if (_dtmManager == null) {
489                      _dtmManager =
490                          (XSLTCDTMManager)_tfactory.getDTMManagerClass()
491                                                    .newInstance();
492                  }
493                  dom = (DOM)_dtmManager.getDTM(source, false, wsfilter, true,
494                                               false, false, 0, hasIdCall);
495             } else if (_dom != null) {
496                  dom = _dom;
497                  _dom = null; // use only once, so reset to 'null'
498
} else {
499                  return null;
500             }
501
502             if (!_isIdentity) {
503                 // Give the translet the opportunity to make a prepass of
504
// the document, in case it can extract useful information early
505
_translet.prepassDocument(dom);
506             }
507
508             return dom;
509
510         }
511         catch (Exception JavaDoc e) {
512             if (_errorListener != null) {
513                 postErrorToListener(e.getMessage());
514             }
515             throw new TransformerException JavaDoc(e);
516         }
517     }
518  
519     /**
520      * Returns the {@link com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl}
521      * object that create this <code>Transformer</code>.
522      */

523     protected TransformerFactoryImpl getTransformerFactory() {
524         return _tfactory;
525     }
526
527     /**
528      * Returns the {@link com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory}
529      * object that create the <code>TransletOutputHandler</code>.
530      */

531     protected TransletOutputHandlerFactory getTransletOutputHandlerFactory() {
532         return _tohFactory;
533     }
534
535     private void transformIdentity(Source JavaDoc source, SerializationHandler handler)
536     throws Exception JavaDoc
537     {
538         // Get systemId from source
539
if (source != null) {
540             _sourceSystemId = source.getSystemId();
541         }
542
543         if (source instanceof StreamSource JavaDoc) {
544             final StreamSource JavaDoc stream = (StreamSource JavaDoc) source;
545             final InputStream JavaDoc streamInput = stream.getInputStream();
546             final Reader JavaDoc streamReader = stream.getReader();
547             final XMLReader JavaDoc reader = _readerManager.getXMLReader();
548
549             try {
550                 // Hook up reader and output handler
551
try {
552                     reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
553             reader.setFeature(NAMESPACE_PREFIXES_FEATURE, true);
554                 }
555                 catch (SAXException JavaDoc e) {
556                     // Falls through
557
}
558                 reader.setContentHandler(handler);
559
560                 // Create input source from source
561
InputSource JavaDoc input;
562                 if (streamInput != null) {
563                     input = new InputSource JavaDoc(streamInput);
564                     input.setSystemId(_sourceSystemId);
565                 }
566                 else if (streamReader != null) {
567                     input = new InputSource JavaDoc(streamReader);
568                     input.setSystemId(_sourceSystemId);
569                 }
570                 else if (_sourceSystemId != null) {
571                     input = new InputSource JavaDoc(_sourceSystemId);
572                 }
573                 else {
574                     ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR);
575                     throw new TransformerException JavaDoc(err.toString());
576                 }
577
578                 // Start pushing SAX events
579
reader.parse(input);
580             } finally {
581                 _readerManager.releaseXMLReader(reader);
582             }
583         } else if (source instanceof SAXSource JavaDoc) {
584             final SAXSource JavaDoc sax = (SAXSource JavaDoc) source;
585             XMLReader JavaDoc reader = sax.getXMLReader();
586             final InputSource JavaDoc input = sax.getInputSource();
587             boolean userReader = true;
588
589             try {
590                 // Create a reader if not set by user
591
if (reader == null) {
592                     reader = _readerManager.getXMLReader();
593                     userReader = false;
594                 }
595
596                 // Hook up reader and output handler
597
try {
598                     reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
599             reader.setFeature(NAMESPACE_PREFIXES_FEATURE, true);
600                 }
601                 catch (SAXException JavaDoc e) {
602                     // Falls through
603
}
604                 reader.setContentHandler(handler);
605
606                 // Start pushing SAX events
607
reader.parse(input);
608             } finally {
609                 if (!userReader) {
610                     _readerManager.releaseXMLReader(reader);
611                 }
612             }
613         } else if (source instanceof DOMSource JavaDoc) {
614             final DOMSource JavaDoc domsrc = (DOMSource JavaDoc) source;
615             new DOM2TO(domsrc.getNode(), handler).parse();
616         } else if (source instanceof XSLTCSource) {
617             final DOM dom = ((XSLTCSource) source).getDOM(null, _translet);
618             ((SAXImpl)dom).copy(handler);
619         } else {
620             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR);
621             throw new TransformerException JavaDoc(err.toString());
622         }
623     }
624
625     /**
626      * Internal transformation method - uses the internal APIs of XSLTC
627      */

628     private void transform(Source JavaDoc source, SerializationHandler handler,
629     String JavaDoc encoding) throws TransformerException JavaDoc
630     {
631     try {
632             /*
633              * According to JAXP1.2, new SAXSource()/StreamSource()
634              * should create an empty input tree, with a default root node.
635              * new DOMSource()creates an empty document using DocumentBuilder.
636              * newDocument(); Use DocumentBuilder.newDocument() for all 3
637              * situations, since there is no clear spec. how to create
638              * an empty tree when both SAXSource() and StreamSource() are used.
639              */

640             if ((source instanceof StreamSource JavaDoc && source.getSystemId()==null
641                 && ((StreamSource JavaDoc)source).getInputStream()==null &&
642                 ((StreamSource JavaDoc)source).getReader()==null)||
643                 (source instanceof SAXSource JavaDoc &&
644                 ((SAXSource JavaDoc)source).getInputSource()==null &&
645                 ((SAXSource JavaDoc)source).getXMLReader()==null )||
646                 (source instanceof DOMSource JavaDoc &&
647                 ((DOMSource JavaDoc)source).getNode()==null)){
648                         DocumentBuilderFactory JavaDoc builderF =
649                                 DocumentBuilderFactory.newInstance();
650                         DocumentBuilder JavaDoc builder =
651                                 builderF.newDocumentBuilder();
652                         String JavaDoc systemID = source.getSystemId();
653                         source = new DOMSource JavaDoc(builder.newDocument());
654
655                         // Copy system ID from original, empty Source to new
656
if (systemID != null) {
657                           source.setSystemId(systemID);
658                         }
659             }
660         if (_isIdentity) {
661         transformIdentity(source, handler);
662         } else {
663         _translet.transform(getDOM(source), handler);
664         }
665     } catch (TransletException e) {
666         if (_errorListener != null) postErrorToListener(e.getMessage());
667         throw new TransformerException JavaDoc(e);
668     } catch (RuntimeException JavaDoc e) {
669         if (_errorListener != null) postErrorToListener(e.getMessage());
670         throw new TransformerException JavaDoc(e);
671     } catch (Exception JavaDoc e) {
672         if (_errorListener != null) postErrorToListener(e.getMessage());
673         throw new TransformerException JavaDoc(e);
674     } finally {
675             _dtmManager = null;
676         }
677     }
678
679     /**
680      * Implements JAXP's Transformer.getErrorListener()
681      * Get the error event handler in effect for the transformation.
682      *
683      * @return The error event handler currently in effect
684      */

685     public ErrorListener JavaDoc getErrorListener() {
686     return _errorListener;
687     }
688
689     /**
690      * Implements JAXP's Transformer.setErrorListener()
691      * Set the error event listener in effect for the transformation.
692      * Register a message handler in the translet in order to forward
693      * xsl:messages to error listener.
694      *
695      * @param listener The error event listener to use
696      * @throws IllegalArgumentException
697      */

698     public void setErrorListener(ErrorListener JavaDoc listener)
699     throws IllegalArgumentException JavaDoc {
700         if (listener == null) {
701         ErrorMsg err = new ErrorMsg(ErrorMsg.ERROR_LISTENER_NULL_ERR,
702                     "Transformer");
703             throw new IllegalArgumentException JavaDoc(err.toString());
704     }
705         _errorListener = listener;
706         
707     // Register a message handler to report xsl:messages
708
if (_translet != null)
709         _translet.setMessageHandler(new MessageHandler(_errorListener));
710     }
711
712     /**
713      * Inform TrAX error listener of an error
714      */

715     private void postErrorToListener(String JavaDoc message) {
716         try {
717             _errorListener.error(new TransformerException JavaDoc(message));
718     }
719     catch (TransformerException JavaDoc e) {
720             // ignored - transformation cannot be continued
721
}
722     }
723
724     /**
725      * Inform TrAX error listener of a warning
726      */

727     private void postWarningToListener(String JavaDoc message) {
728         try {
729             _errorListener.warning(new TransformerException JavaDoc(message));
730         }
731     catch (TransformerException JavaDoc e) {
732             // ignored - transformation cannot be continued
733
}
734     }
735
736     /**
737      * The translet stores all CDATA sections set in the <xsl:output> element
738      * in a Hashtable. This method will re-construct the whitespace separated
739      * list of elements given in the <xsl:output> element.
740      */

741     private String JavaDoc makeCDATAString(Hashtable cdata) {
742     // Return a 'null' string if no CDATA section elements were specified
743
if (cdata == null) return null;
744
745     StringBuffer JavaDoc result = new StringBuffer JavaDoc();
746
747     // Get an enumeration of all the elements in the hashtable
748
Enumeration JavaDoc elements = cdata.keys();
749     if (elements.hasMoreElements()) {
750         result.append((String JavaDoc)elements.nextElement());
751         while (elements.hasMoreElements()) {
752         String JavaDoc element = (String JavaDoc)elements.nextElement();
753         result.append(' ');
754         result.append(element);
755         }
756     }
757     
758     return(result.toString());
759     }
760
761     /**
762      * Implements JAXP's Transformer.getOutputProperties().
763      * Returns a copy of the output properties for the transformation. This is
764      * a set of layered properties. The first layer contains properties set by
765      * calls to setOutputProperty() and setOutputProperties() on this class,
766      * and the output settings defined in the stylesheet's <xsl:output>
767      * element makes up the second level, while the default XSLT output
768      * settings are returned on the third level.
769      *
770      * @return Properties in effect for this Transformer
771      */

772     public Properties JavaDoc getOutputProperties() {
773     return (Properties JavaDoc) _properties.clone();
774     }
775
776     /**
777      * Implements JAXP's Transformer.getOutputProperty().
778      * Get an output property that is in effect for the transformation. The
779      * property specified may be a property that was set with setOutputProperty,
780      * or it may be a property specified in the stylesheet.
781      *
782      * @param name A non-null string that contains the name of the property
783      * @throws IllegalArgumentException if the property name is not known
784      */

785     public String JavaDoc getOutputProperty(String JavaDoc name)
786     throws IllegalArgumentException JavaDoc
787     {
788     if (!validOutputProperty(name)) {
789         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
790         throw new IllegalArgumentException JavaDoc(err.toString());
791     }
792     return _properties.getProperty(name);
793     }
794
795     /**
796      * Implements JAXP's Transformer.setOutputProperties().
797      * Set the output properties for the transformation. These properties
798      * will override properties set in the Templates with xsl:output.
799      * Unrecognised properties will be quitely ignored.
800      *
801      * @param properties The properties to use for the Transformer
802      * @throws IllegalArgumentException Never, errors are ignored
803      */

804     public void setOutputProperties(Properties JavaDoc properties)
805     throws IllegalArgumentException JavaDoc
806     {
807     if (properties != null) {
808         final Enumeration JavaDoc names = properties.propertyNames();
809
810         while (names.hasMoreElements()) {
811         final String JavaDoc name = (String JavaDoc) names.nextElement();
812
813         // Ignore lower layer properties
814
if (isDefaultProperty(name, properties)) continue;
815
816         if (validOutputProperty(name)) {
817             _properties.setProperty(name, properties.getProperty(name));
818         }
819         else {
820             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
821             throw new IllegalArgumentException JavaDoc(err.toString());
822         }
823         }
824     }
825     else {
826         _properties = _propertiesClone;
827     }
828     }
829
830     /**
831      * Implements JAXP's Transformer.setOutputProperty().
832      * Get an output property that is in effect for the transformation. The
833      * property specified may be a property that was set with
834      * setOutputProperty(), or it may be a property specified in the stylesheet.
835      *
836      * @param name The name of the property to set
837      * @param value The value to assign to the property
838      * @throws IllegalArgumentException Never, errors are ignored
839      */

840     public void setOutputProperty(String JavaDoc name, String JavaDoc value)
841     throws IllegalArgumentException JavaDoc
842     {
843     if (!validOutputProperty(name)) {
844         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
845         throw new IllegalArgumentException JavaDoc(err.toString());
846     }
847     _properties.setProperty(name, value);
848     }
849
850     /**
851      * Internal method to pass any properties to the translet prior to
852      * initiating the transformation
853      */

854     private void transferOutputProperties(AbstractTranslet translet)
855     {
856     // Return right now if no properties are set
857
if (_properties == null) return;
858
859     // Get a list of all the defined properties
860
Enumeration JavaDoc names = _properties.propertyNames();
861     while (names.hasMoreElements()) {
862         // Note the use of get() instead of getProperty()
863
String JavaDoc name = (String JavaDoc) names.nextElement();
864         String JavaDoc value = (String JavaDoc) _properties.get(name);
865
866         // Ignore default properties
867
if (value == null) continue;
868
869         // Pass property value to translet - override previous setting
870
if (name.equals(OutputKeys.ENCODING)) {
871         translet._encoding = value;
872         }
873         else if (name.equals(OutputKeys.METHOD)) {
874         translet._method = value;
875         }
876         else if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) {
877         translet._doctypePublic = value;
878         }
879         else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) {
880         translet._doctypeSystem = value;
881         }
882         else if (name.equals(OutputKeys.MEDIA_TYPE)) {
883         translet._mediaType = value;
884         }
885         else if (name.equals(OutputKeys.STANDALONE)) {
886         translet._standalone = value;
887         }
888         else if (name.equals(OutputKeys.VERSION)) {
889         translet._version = value;
890         }
891         else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) {
892         translet._omitHeader =
893             (value != null && value.toLowerCase().equals("yes"));
894         }
895         else if (name.equals(OutputKeys.INDENT)) {
896         translet._indent =
897             (value != null && value.toLowerCase().equals("yes"));
898         }
899         else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
900         if (value != null) {
901             translet._cdata = null; // clear previous setting
902
StringTokenizer JavaDoc e = new StringTokenizer JavaDoc(value);
903             while (e.hasMoreTokens()) {
904             translet.addCdataElement(e.nextToken());
905             }
906         }
907         }
908     }
909     }
910
911     /**
912      * This method is used to pass any properties to the output handler
913      * when running the identity transform.
914      */

915     public void transferOutputProperties(SerializationHandler handler)
916     {
917     // Return right now if no properties are set
918
if (_properties == null) return;
919
920     String JavaDoc doctypePublic = null;
921     String JavaDoc doctypeSystem = null;
922
923     // Get a list of all the defined properties
924
Enumeration JavaDoc names = _properties.propertyNames();
925     while (names.hasMoreElements()) {
926         // Note the use of get() instead of getProperty()
927
String JavaDoc name = (String JavaDoc) names.nextElement();
928         String JavaDoc value = (String JavaDoc) _properties.get(name);
929
930         // Ignore default properties
931
if (value == null) continue;
932
933         // Pass property value to translet - override previous setting
934
if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) {
935         doctypePublic = value;
936         }
937         else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) {
938         doctypeSystem = value;
939         }
940         else if (name.equals(OutputKeys.MEDIA_TYPE)) {
941         handler.setMediaType(value);
942         }
943         else if (name.equals(OutputKeys.STANDALONE)) {
944         handler.setStandalone(value);
945         }
946         else if (name.equals(OutputKeys.VERSION)) {
947         handler.setVersion(value);
948         }
949         else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) {
950         handler.setOmitXMLDeclaration(
951             value != null && value.toLowerCase().equals("yes"));
952         }
953         else if (name.equals(OutputKeys.INDENT)) {
954         handler.setIndent(
955             value != null && value.toLowerCase().equals("yes"));
956         }
957         else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
958         if (value != null) {
959             StringTokenizer JavaDoc e = new StringTokenizer JavaDoc(value);
960                     Vector JavaDoc uriAndLocalNames = null;
961             while (e.hasMoreTokens()) {
962             final String JavaDoc token = e.nextToken();
963
964                         // look for the last colon, as the String may be
965
// something like "http://abc.com:local"
966
int lastcolon = token.lastIndexOf(':');
967                         String JavaDoc uri;
968                         String JavaDoc localName;
969                         if (lastcolon > 0) {
970                             uri = token.substring(0, lastcolon);
971                             localName = token.substring(lastcolon+1);
972                         } else {
973                             // no colon at all, lets hope this is the
974
// local name itself then
975
uri = null;
976                             localName = token;
977                         }
978
979                         if (uriAndLocalNames == null) {
980                             uriAndLocalNames = new Vector JavaDoc();
981                         }
982                         // add the uri/localName as a pair, in that order
983
uriAndLocalNames.addElement(uri);
984                         uriAndLocalNames.addElement(localName);
985                     }
986                     handler.setCdataSectionElements(uriAndLocalNames);
987         }
988         }
989     }
990
991     // Call setDoctype() if needed
992
if (doctypePublic != null || doctypeSystem != null) {
993         handler.setDoctype(doctypeSystem, doctypePublic);
994     }
995     }
996
997     /**
998      * Internal method to create the initial set of properties. There
999      * are two layers of properties: the default layer and the base layer.
1000     * The latter contains properties defined in the stylesheet or by
1001     * the user using this API.
1002     */

1003    private Properties JavaDoc createOutputProperties(Properties JavaDoc outputProperties) {
1004    final Properties JavaDoc defaults = new Properties JavaDoc();
1005    setDefaults(defaults, "xml");
1006
1007    // Copy propeties set in stylesheet to base
1008
final Properties JavaDoc base = new Properties JavaDoc(defaults);
1009    if (outputProperties != null) {
1010        final Enumeration JavaDoc names = outputProperties.propertyNames();
1011        while (names.hasMoreElements()) {
1012        final String JavaDoc name = (String JavaDoc) names.nextElement();
1013        base.setProperty(name, outputProperties.getProperty(name));
1014        }
1015    }
1016    else {
1017        base.setProperty(OutputKeys.ENCODING, _translet._encoding);
1018        if (_translet._method != null)
1019            base.setProperty(OutputKeys.METHOD, _translet._method);
1020    }
1021
1022    // Update defaults based on output method
1023
final String JavaDoc method = base.getProperty(OutputKeys.METHOD);
1024    if (method != null) {
1025        if (method.equals("html")) {
1026            setDefaults(defaults,"html");
1027        }
1028        else if (method.equals("text")) {
1029            setDefaults(defaults,"text");
1030        }
1031    }
1032
1033    return base;
1034    }
1035
1036    /**
1037     * Internal method to get the default properties from the
1038     * serializer factory and set them on the property object.
1039     * @param props a java.util.Property object on which the properties are set.
1040     * @param method The output method type, one of "xml", "text", "html" ...
1041     */

1042    private void setDefaults(Properties JavaDoc props, String JavaDoc method)
1043    {
1044        final Properties JavaDoc method_props =
1045            OutputPropertiesFactory.getDefaultMethodProperties(method);
1046        {
1047            final Enumeration JavaDoc names = method_props.propertyNames();
1048            while (names.hasMoreElements())
1049            {
1050                final String JavaDoc name = (String JavaDoc)names.nextElement();
1051                props.setProperty(name, method_props.getProperty(name));
1052            }
1053        }
1054    }
1055    /**
1056     * Verifies if a given output property name is a property defined in
1057     * the JAXP 1.1 / TrAX spec
1058     */

1059    private boolean validOutputProperty(String JavaDoc name) {
1060    return (name.equals(OutputKeys.ENCODING) ||
1061        name.equals(OutputKeys.METHOD) ||
1062        name.equals(OutputKeys.INDENT) ||
1063        name.equals(OutputKeys.DOCTYPE_PUBLIC) ||
1064        name.equals(OutputKeys.DOCTYPE_SYSTEM) ||
1065        name.equals(OutputKeys.CDATA_SECTION_ELEMENTS) ||
1066        name.equals(OutputKeys.MEDIA_TYPE) ||
1067        name.equals(OutputKeys.OMIT_XML_DECLARATION) ||
1068        name.equals(OutputKeys.STANDALONE) ||
1069        name.equals(OutputKeys.VERSION) ||
1070        name.charAt(0) == '{');
1071    }
1072
1073    /**
1074     * Checks if a given output property is default (2nd layer only)
1075     */

1076    private boolean isDefaultProperty(String JavaDoc name, Properties JavaDoc properties) {
1077    return (properties.get(name) == null);
1078    }
1079
1080    /**
1081     * Implements JAXP's Transformer.setParameter()
1082     * Add a parameter for the transformation. The parameter is simply passed
1083     * on to the translet - no validation is performed - so any unused
1084     * parameters are quitely ignored by the translet.
1085     *
1086     * @param name The name of the parameter
1087     * @param value The value to assign to the parameter
1088     */

1089    public void setParameter(String JavaDoc name, Object JavaDoc value) {
1090        
1091        if (value == null) {
1092            ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_INVALID_SET_PARAM_VALUE, name);
1093            throw new IllegalArgumentException JavaDoc(err.toString());
1094        }
1095             
1096    if (_isIdentity) {
1097        if (_parameters == null) {
1098        _parameters = new Hashtable();
1099        }
1100        _parameters.put(name, value);
1101    }
1102    else {
1103        _translet.addParameter(name, value);
1104    }
1105    }
1106
1107    /**
1108     * Implements JAXP's Transformer.clearParameters()
1109     * Clear all parameters set with setParameter. Clears the translet's
1110     * parameter stack.
1111     */

1112    public void clearParameters() {
1113    if (_isIdentity && _parameters != null) {
1114        _parameters.clear();
1115    }
1116    else {
1117        _translet.clearParameters();
1118    }
1119    }
1120
1121    /**
1122     * Implements JAXP's Transformer.getParameter()
1123     * Returns the value of a given parameter. Note that the translet will not
1124     * keep values for parameters that were not defined in the stylesheet.
1125     *
1126     * @param name The name of the parameter
1127     * @return An object that contains the value assigned to the parameter
1128     */

1129    public final Object JavaDoc getParameter(String JavaDoc name) {
1130    if (_isIdentity) {
1131        return (_parameters != null) ? _parameters.get(name) : null;
1132    }
1133    else {
1134        return _translet.getParameter(name);
1135    }
1136    }
1137
1138    /**
1139     * Implements JAXP's Transformer.getURIResolver()
1140     * Set the object currently used to resolve URIs used in document().
1141     *
1142     * @return The URLResolver object currently in use
1143     */

1144    public URIResolver JavaDoc getURIResolver() {
1145    return _uriResolver;
1146    }
1147
1148    /**
1149     * Implements JAXP's Transformer.setURIResolver()
1150     * Set an object that will be used to resolve URIs used in document().
1151     *
1152     * @param resolver The URIResolver to use in document()
1153     */

1154    public void setURIResolver(URIResolver JavaDoc resolver) {
1155    _uriResolver = resolver;
1156    }
1157
1158    /**
1159     * This class should only be used as a DOMCache for the translet if the
1160     * URIResolver has been set.
1161     *
1162     * The method implements XSLTC's DOMCache interface, which is used to
1163     * plug in an external document loader into a translet. This method acts
1164     * as an adapter between TrAX's URIResolver interface and XSLTC's
1165     * DOMCache interface. This approach is simple, but removes the
1166     * possibility of using external document caches with XSLTC.
1167     *
1168     * @param baseURI The base URI used by the document call.
1169     * @param href The href argument passed to the document function.
1170     * @param translet A reference to the translet requesting the document
1171     */

1172    public DOM retrieveDocument(String JavaDoc baseURI, String JavaDoc href, Translet translet) {
1173    try {
1174            // Argument to document function was: document('');
1175
if (href.length() == 0) {
1176                href = new String JavaDoc(baseURI);
1177            }
1178
1179            /*
1180             * Fix for bug 24188
1181             * Incase the _uriResolver.resolve(href,base) is null
1182             * try to still retrieve the document before returning null
1183             * and throwing the FileNotFoundException in
1184             * com.sun.org.apache.xalan.internal.xsltc.dom.LoadDocument
1185             *
1186             */

1187            Source JavaDoc resolvedSource = _uriResolver.resolve(href, baseURI);
1188            if (resolvedSource == null) {
1189                StreamSource JavaDoc streamSource = new StreamSource JavaDoc(
1190                     SystemIDResolver.getAbsoluteURI(href, baseURI));
1191                return getDOM(streamSource) ;
1192            }
1193
1194            return getDOM(resolvedSource);
1195    }
1196    catch (TransformerException JavaDoc e) {
1197        if (_errorListener != null)
1198        postErrorToListener("File not found: " + e.getMessage());
1199        return(null);
1200    }
1201    }
1202
1203    /**
1204     * Receive notification of a recoverable error.
1205     * The transformer must continue to provide normal parsing events after
1206     * invoking this method. It should still be possible for the application
1207     * to process the document through to the end.
1208     *
1209     * @param exception The warning information encapsulated in a transformer
1210     * exception.
1211     * @throws TransformerException if the application chooses to discontinue
1212     * the transformation (always does in our case).
1213     */

1214    public void error(TransformerException JavaDoc e)
1215    throws TransformerException JavaDoc
1216    {
1217        Throwable JavaDoc wrapped = e.getException();
1218        if (wrapped != null) {
1219            System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG,
1220                                            e.getMessageAndLocation(),
1221                                            wrapped.getMessage()));
1222        } else {
1223            System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG,
1224                                            e.getMessageAndLocation()));
1225        }
1226        throw e;
1227    }
1228
1229    /**
1230     * Receive notification of a non-recoverable error.
1231     * The application must assume that the transformation cannot continue
1232     * after the Transformer has invoked this method, and should continue
1233     * (if at all) only to collect addition error messages. In fact,
1234     * Transformers are free to stop reporting events once this method has
1235     * been invoked.
1236     *
1237     * @param exception The warning information encapsulated in a transformer
1238     * exception.
1239     * @throws TransformerException if the application chooses to discontinue
1240     * the transformation (always does in our case).
1241     */

1242    public void fatalError(TransformerException JavaDoc e)
1243    throws TransformerException JavaDoc
1244    {
1245        Throwable JavaDoc wrapped = e.getException();
1246        if (wrapped != null) {
1247            System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG,
1248                                            e.getMessageAndLocation(),
1249                                            wrapped.getMessage()));
1250        } else {
1251            System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG,
1252                                            e.getMessageAndLocation()));
1253        }
1254        throw e;
1255    }
1256
1257    /**
1258     * Receive notification of a warning.
1259     * Transformers can use this method to report conditions that are not
1260     * errors or fatal errors. The default behaviour is to take no action.
1261     * After invoking this method, the Transformer must continue with the
1262     * transformation. It should still be possible for the application to
1263     * process the document through to the end.
1264     *
1265     * @param exception The warning information encapsulated in a transformer
1266     * exception.
1267     * @throws TransformerException if the application chooses to discontinue
1268     * the transformation (never does in our case).
1269     */

1270    public void warning(TransformerException JavaDoc e)
1271    throws TransformerException JavaDoc
1272    {
1273        Throwable JavaDoc wrapped = e.getException();
1274        if (wrapped != null) {
1275            System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG,
1276                                            e.getMessageAndLocation(),
1277                                            wrapped.getMessage()));
1278        } else {
1279            System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG,
1280                                            e.getMessageAndLocation()));
1281        }
1282    }
1283
1284
1285    /**
1286     * This method resets the Transformer to its original configuration
1287     * Transformer code is reset to the same state it was when it was
1288     * created
1289     * @since 1.5
1290     */

1291    public void reset() {
1292
1293        _method = null;
1294        _encoding = null;
1295        _sourceSystemId = null;
1296        _errorListener = this;
1297        _uriResolver = null;
1298        _dom = null;
1299        _parameters = null;
1300        _indentNumber = 0;
1301        setOutputProperties (null);
1302
1303    }
1304 
1305
1306
1307}
1308
Popular Tags