KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > trax > TransformerFactoryImpl


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: TransformerFactoryImpl.java,v 1.73 2004/02/23 10:29:36 aruny Exp $
18  */

19
20 package org.apache.xalan.xsltc.trax;
21
22 import java.io.File JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.FileNotFoundException JavaDoc;
25 import java.io.FilenameFilter JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.net.MalformedURLException JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.util.Enumeration JavaDoc;
31 import java.util.Hashtable JavaDoc;
32 import java.util.Properties JavaDoc;
33 import java.util.Vector JavaDoc;
34 import java.util.zip.ZipEntry JavaDoc;
35 import java.util.zip.ZipFile JavaDoc;
36
37 import javax.xml.parsers.SAXParserFactory JavaDoc;
38 import javax.xml.parsers.SAXParser JavaDoc;
39 import javax.xml.parsers.ParserConfigurationException JavaDoc;
40
41 import javax.xml.transform.ErrorListener JavaDoc;
42 import javax.xml.transform.Source JavaDoc;
43 import javax.xml.transform.Templates JavaDoc;
44 import javax.xml.transform.Transformer JavaDoc;
45 import javax.xml.transform.TransformerConfigurationException JavaDoc;
46 import javax.xml.transform.TransformerException JavaDoc;
47 import javax.xml.transform.URIResolver JavaDoc;
48 import javax.xml.transform.dom.DOMResult JavaDoc;
49 import javax.xml.transform.dom.DOMSource JavaDoc;
50 import javax.xml.transform.sax.SAXResult JavaDoc;
51 import javax.xml.transform.sax.SAXSource JavaDoc;
52 import javax.xml.transform.sax.SAXTransformerFactory JavaDoc;
53 import javax.xml.transform.sax.TemplatesHandler JavaDoc;
54 import javax.xml.transform.sax.TransformerHandler JavaDoc;
55 import javax.xml.transform.stream.StreamResult JavaDoc;
56 import javax.xml.transform.stream.StreamSource JavaDoc;
57
58 import org.apache.xml.utils.StylesheetPIHandler;
59 import org.apache.xml.utils.StopParseException;
60
61 import org.apache.xalan.xsltc.compiler.SourceLoader;
62 import org.apache.xalan.xsltc.compiler.XSLTC;
63 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
64 import org.apache.xalan.xsltc.dom.XSLTCDTMManager;
65
66
67 import org.xml.sax.InputSource JavaDoc;
68 import org.xml.sax.XMLFilter JavaDoc;
69 import org.xml.sax.XMLReader JavaDoc;
70 import org.xml.sax.helpers.XMLReaderFactory JavaDoc;
71
72 /**
73  * Implementation of a JAXP1.1 TransformerFactory for Translets.
74  * @author G. Todd Miller
75  * @author Morten Jorgensen
76  * @author Santiago Pericas-Geertsen
77  */

78 public class TransformerFactoryImpl
79     extends SAXTransformerFactory JavaDoc implements SourceLoader, ErrorListener JavaDoc
80 {
81     // Public constants for attributes supported by the XSLTC TransformerFactory.
82
public final static String JavaDoc TRANSLET_NAME = "translet-name";
83     public final static String JavaDoc DESTINATION_DIRECTORY = "destination-directory";
84     public final static String JavaDoc PACKAGE_NAME = "package-name";
85     public final static String JavaDoc JAR_NAME = "jar-name";
86     public final static String JavaDoc GENERATE_TRANSLET = "generate-translet";
87     public final static String JavaDoc AUTO_TRANSLET = "auto-translet";
88     public final static String JavaDoc USE_CLASSPATH = "use-classpath";
89     public final static String JavaDoc DEBUG = "debug";
90     public final static String JavaDoc ENABLE_INLINING = "enable-inlining";
91     public final static String JavaDoc INDENT_NUMBER = "indent-number";
92         
93     /**
94      * This error listener is used only for this factory and is not passed to
95      * the Templates or Transformer objects that we create.
96      */

97     private ErrorListener JavaDoc _errorListener = this;
98
99     /**
100      * This URIResolver is passed to all created Templates and Transformers
101      */

102     private URIResolver JavaDoc _uriResolver = null;
103
104     /**
105      * As Gregor Samsa awoke one morning from uneasy dreams he found himself
106      * transformed in his bed into a gigantic insect. He was lying on his hard,
107      * as it were armour plated, back, and if he lifted his head a little he
108      * could see his big, brown belly divided into stiff, arched segments, on
109      * top of which the bed quilt could hardly keep in position and was about
110      * to slide off completely. His numerous legs, which were pitifully thin
111      * compared to the rest of his bulk, waved helplessly before his eyes.
112      * "What has happened to me?", he thought. It was no dream....
113      */

114     protected static String JavaDoc DEFAULT_TRANSLET_NAME = "GregorSamsa";
115     
116     /**
117      * The class name of the translet
118      */

119     private String JavaDoc _transletName = DEFAULT_TRANSLET_NAME;
120     
121     /**
122      * The destination directory for the translet
123      */

124     private String JavaDoc _destinationDirectory = null;
125     
126     /**
127      * The package name prefix for all generated translet classes
128      */

129     private String JavaDoc _packageName = null;
130     
131     /**
132      * The jar file name which the translet classes are packaged into
133      */

134     private String JavaDoc _jarFileName = null;
135
136     /**
137      * This Hashtable is used to store parameters for locating
138      * <?xml-stylesheet ...?> processing instructions in XML docs.
139      */

140     private Hashtable JavaDoc _piParams = null;
141
142
143     /**
144      * Use a thread local variable to store a copy of an XML Reader.
145      */

146     static ThreadLocal JavaDoc _xmlReader = new ThreadLocal JavaDoc();
147
148     /**
149      * The above hashtable stores objects of this class.
150      */

151     private static class PIParamWrapper {
152     public String JavaDoc _media = null;
153     public String JavaDoc _title = null;
154     public String JavaDoc _charset = null;
155     
156     public PIParamWrapper(String JavaDoc media, String JavaDoc title, String JavaDoc charset) {
157         _media = media;
158         _title = title;
159         _charset = charset;
160     }
161     }
162
163     /**
164      * Set to <code>true</code> when debugging is enabled.
165      */

166     private boolean _debug = false;
167
168     /**
169      * Set to <code>true</code> when templates are inlined.
170      */

171     private boolean _enableInlining = false;
172     
173     /**
174      * Set to <code>true</code> when we want to generate
175      * translet classes from the stylesheet.
176      */

177     private boolean _generateTranslet = false;
178     
179     /**
180      * If this is set to <code>true</code>, we attempt to use translet classes
181      * for transformation if possible without compiling the stylesheet. The
182      * translet class is only used if its timestamp is newer than the timestamp
183      * of the stylesheet.
184      */

185     private boolean _autoTranslet = false;
186     
187     /**
188      * If this is set to <code>true</code>, we attempt to load the translet
189      * from the CLASSPATH.
190      */

191     private boolean _useClasspath = false;
192
193     /**
194      * Number of indent spaces when indentation is turned on.
195      */

196     private int _indentNumber = -1;
197
198     /**
199      * The provider of the XSLTC DTM Manager service. This is fixed for any
200      * instance of this class. In order to change service providers, a new
201      * XSLTC <code>TransformerFactory</code> must be instantiated.
202      * @see XSLTCDTMManager#getDTMManagerClass()
203      */

204     private Class JavaDoc m_DTMManagerClass;
205
206     /**
207      * javax.xml.transform.sax.TransformerFactory implementation.
208      */

209     public TransformerFactoryImpl() {
210         m_DTMManagerClass = XSLTCDTMManager.getDTMManagerClass();
211     }
212
213     /**
214      * javax.xml.transform.sax.TransformerFactory implementation.
215      * Set the error event listener for the TransformerFactory, which is used
216      * for the processing of transformation instructions, and not for the
217      * transformation itself.
218      *
219      * @param listener The error listener to use with the TransformerFactory
220      * @throws IllegalArgumentException
221      */

222     public void setErrorListener(ErrorListener JavaDoc listener)
223     throws IllegalArgumentException JavaDoc
224     {
225     if (listener == null) {
226         ErrorMsg err = new ErrorMsg(ErrorMsg.ERROR_LISTENER_NULL_ERR,
227                     "TransformerFactory");
228             throw new IllegalArgumentException JavaDoc(err.toString());
229     }
230     _errorListener = listener;
231     }
232
233     /**
234      * javax.xml.transform.sax.TransformerFactory implementation.
235      * Get the error event handler for the TransformerFactory.
236      *
237      * @return The error listener used with the TransformerFactory
238      */

239     public ErrorListener JavaDoc getErrorListener() {
240     return _errorListener;
241     }
242
243     /**
244      * javax.xml.transform.sax.TransformerFactory implementation.
245      * Returns the value set for a TransformerFactory attribute
246      *
247      * @param name The attribute name
248      * @return An object representing the attribute value
249      * @throws IllegalArgumentException
250      */

251     public Object JavaDoc getAttribute(String JavaDoc name)
252     throws IllegalArgumentException JavaDoc
253     {
254     // Return value for attribute 'translet-name'
255
if (name.equals(TRANSLET_NAME)) {
256         return _transletName;
257     }
258     else if (name.equals(GENERATE_TRANSLET)) {
259         return new Boolean JavaDoc(_generateTranslet);
260     }
261     else if (name.equals(AUTO_TRANSLET)) {
262         return new Boolean JavaDoc(_autoTranslet);
263     }
264
265     // Throw an exception for all other attributes
266
ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_INVALID_ATTR_ERR, name);
267     throw new IllegalArgumentException JavaDoc(err.toString());
268     }
269
270     /**
271      * javax.xml.transform.sax.TransformerFactory implementation.
272      * Sets the value for a TransformerFactory attribute.
273      *
274      * @param name The attribute name
275      * @param value An object representing the attribute value
276      * @throws IllegalArgumentException
277      */

278     public void setAttribute(String JavaDoc name, Object JavaDoc value)
279     throws IllegalArgumentException JavaDoc
280     {
281     // Set the default translet name (ie. class name), which will be used
282
// for translets that cannot be given a name from their system-id.
283
if (name.equals(TRANSLET_NAME) && value instanceof String JavaDoc) {
284         _transletName = (String JavaDoc) value;
285         return;
286     }
287     else if (name.equals(DESTINATION_DIRECTORY) && value instanceof String JavaDoc) {
288         _destinationDirectory = (String JavaDoc) value;
289         return;
290     }
291     else if (name.equals(PACKAGE_NAME) && value instanceof String JavaDoc) {
292         _packageName = (String JavaDoc) value;
293         return;
294     }
295     else if (name.equals(JAR_NAME) && value instanceof String JavaDoc) {
296         _jarFileName = (String JavaDoc) value;
297         return;
298     }
299     else if (name.equals(GENERATE_TRANSLET)) {
300         if (value instanceof Boolean JavaDoc) {
301         _generateTranslet = ((Boolean JavaDoc) value).booleanValue();
302         return;
303         }
304         else if (value instanceof String JavaDoc) {
305         _generateTranslet = ((String JavaDoc) value).equalsIgnoreCase("true");
306         return;
307         }
308     }
309     else if (name.equals(AUTO_TRANSLET)) {
310         if (value instanceof Boolean JavaDoc) {
311         _autoTranslet = ((Boolean JavaDoc) value).booleanValue();
312         return;
313         }
314         else if (value instanceof String JavaDoc) {
315         _autoTranslet = ((String JavaDoc) value).equalsIgnoreCase("true");
316         return;
317         }
318     }
319     else if (name.equals(USE_CLASSPATH)) {
320         if (value instanceof Boolean JavaDoc) {
321         _useClasspath = ((Boolean JavaDoc) value).booleanValue();
322         return;
323         }
324         else if (value instanceof String JavaDoc) {
325         _useClasspath = ((String JavaDoc) value).equalsIgnoreCase("true");
326         return;
327         }
328     }
329     else if (name.equals(DEBUG)) {
330         if (value instanceof Boolean JavaDoc) {
331         _debug = ((Boolean JavaDoc) value).booleanValue();
332         return;
333         }
334         else if (value instanceof String JavaDoc) {
335         _debug = ((String JavaDoc) value).equalsIgnoreCase("true");
336         return;
337         }
338     }
339     else if (name.equals(ENABLE_INLINING)) {
340         if (value instanceof Boolean JavaDoc) {
341         _enableInlining = ((Boolean JavaDoc) value).booleanValue();
342         return;
343         }
344         else if (value instanceof String JavaDoc) {
345         _enableInlining = ((String JavaDoc) value).equalsIgnoreCase("true");
346         return;
347         }
348     }
349     else if (name.equals(INDENT_NUMBER)) {
350         if (value instanceof String JavaDoc) {
351         try {
352             _indentNumber = Integer.parseInt((String JavaDoc) value);
353             return;
354         }
355         catch (NumberFormatException JavaDoc e) {
356             // Falls through
357
}
358         }
359         else if (value instanceof Integer JavaDoc) {
360         _indentNumber = ((Integer JavaDoc) value).intValue();
361         return;
362         }
363     }
364
365     // Throw an exception for all other attributes
366
final ErrorMsg err
367         = new ErrorMsg(ErrorMsg.JAXP_INVALID_ATTR_ERR, name);
368     throw new IllegalArgumentException JavaDoc(err.toString());
369     }
370
371     /**
372      * javax.xml.transform.sax.TransformerFactory implementation.
373      * Look up the value of a feature (to see if it is supported).
374      * This method must be updated as the various methods and features of this
375      * class are implemented.
376      *
377      * @param name The feature name
378      * @return 'true' if feature is supported, 'false' if not
379      */

380     public boolean getFeature(String JavaDoc name) {
381     // All supported features should be listed here
382
String JavaDoc[] features = {
383         DOMSource.FEATURE,
384         DOMResult.FEATURE,
385         SAXSource.FEATURE,
386         SAXResult.FEATURE,
387         StreamSource.FEATURE,
388         StreamResult.FEATURE,
389         SAXTransformerFactory.FEATURE,
390         SAXTransformerFactory.FEATURE_XMLFILTER
391     };
392
393     // Inefficient, but array is small
394
for (int i =0; i < features.length; i++) {
395         if (name.equals(features[i])) {
396         return true;
397         }
398     }
399     // Feature not supported
400
return false;
401     }
402
403     /**
404      * javax.xml.transform.sax.TransformerFactory implementation.
405      * Get the object that is used by default during the transformation to
406      * resolve URIs used in document(), xsl:import, or xsl:include.
407      *
408      * @return The URLResolver used for this TransformerFactory and all
409      * Templates and Transformer objects created using this factory
410      */

411     public URIResolver JavaDoc getURIResolver() {
412     return _uriResolver;
413     }
414
415     /**
416      * javax.xml.transform.sax.TransformerFactory implementation.
417      * Set the object that is used by default during the transformation to
418      * resolve URIs used in document(), xsl:import, or xsl:include. Note that
419      * this does not affect Templates and Transformers that are already
420      * created with this factory.
421      *
422      * @param resolver The URLResolver used for this TransformerFactory and all
423      * Templates and Transformer objects created using this factory
424      */

425     public void setURIResolver(URIResolver JavaDoc resolver) {
426     _uriResolver = resolver;
427     }
428
429     /**
430      * javax.xml.transform.sax.TransformerFactory implementation.
431      * Get the stylesheet specification(s) associated via the xml-stylesheet
432      * processing instruction (see http://www.w3.org/TR/xml-stylesheet/) with
433      * the document document specified in the source parameter, and that match
434      * the given criteria.
435      *
436      * @param source The XML source document.
437      * @param media The media attribute to be matched. May be null, in which
438      * case the prefered templates will be used (i.e. alternate = no).
439      * @param title The value of the title attribute to match. May be null.
440      * @param charset The value of the charset attribute to match. May be null.
441      * @return A Source object suitable for passing to the TransformerFactory.
442      * @throws TransformerConfigurationException
443      */

444     public Source JavaDoc getAssociatedStylesheet(Source JavaDoc source, String JavaDoc media,
445                       String JavaDoc title, String JavaDoc charset)
446     throws TransformerConfigurationException JavaDoc {
447
448         String JavaDoc baseId;
449         XMLReader JavaDoc reader = null;
450         InputSource JavaDoc isource = null;
451
452
453         /**
454          * Fix for bugzilla bug 24187
455          */

456         StylesheetPIHandler _stylesheetPIHandler = new StylesheetPIHandler(null,media,title,charset);
457
458         try {
459   
460             if (source instanceof DOMSource JavaDoc ) {
461                 final DOMSource JavaDoc domsrc = (DOMSource JavaDoc) source;
462                 baseId = domsrc.getSystemId();
463                 final org.w3c.dom.Node JavaDoc node = domsrc.getNode();
464                 final DOM2SAX dom2sax = new DOM2SAX(node);
465
466                 _stylesheetPIHandler.setBaseId(baseId);
467
468                 dom2sax.setContentHandler( _stylesheetPIHandler);
469                 dom2sax.parse();
470             } else {
471                 isource = SAXSource.sourceToInputSource(source);
472                 baseId = isource.getSystemId();
473
474                 SAXParserFactory JavaDoc factory = SAXParserFactory.newInstance();
475                 factory.setNamespaceAware(true);
476                 SAXParser JavaDoc jaxpParser = factory.newSAXParser();
477
478                 reader = jaxpParser.getXMLReader();
479                 if (reader == null) {
480                     reader = XMLReaderFactory.createXMLReader();
481                 }
482
483                 _stylesheetPIHandler.setBaseId(baseId);
484                 reader.setContentHandler(_stylesheetPIHandler);
485                 reader.parse(isource);
486
487             }
488
489             if (_uriResolver != null ) {
490                 _stylesheetPIHandler.setURIResolver(_uriResolver);
491             }
492
493         } catch (StopParseException e ) {
494           // startElement encountered so do not parse further
495

496         } catch (javax.xml.parsers.ParserConfigurationException JavaDoc e) {
497
498              throw new TransformerConfigurationException JavaDoc(
499              "getAssociatedStylesheets failed", e);
500
501         } catch (org.xml.sax.SAXException JavaDoc se) {
502
503              throw new TransformerConfigurationException JavaDoc(
504              "getAssociatedStylesheets failed", se);
505
506
507         } catch (IOException JavaDoc ioe ) {
508            throw new TransformerConfigurationException JavaDoc(
509            "getAssociatedStylesheets failed", ioe);
510
511         }
512
513          return _stylesheetPIHandler.getAssociatedStylesheet();
514
515     }
516
517     /**
518      * javax.xml.transform.sax.TransformerFactory implementation.
519      * Create a Transformer object that copies the input document to the result.
520      *
521      * @return A Transformer object that simply copies the source to the result.
522      * @throws TransformerConfigurationException
523      */

524     public Transformer JavaDoc newTransformer()
525     throws TransformerConfigurationException JavaDoc
526     {
527     TransformerImpl result = new TransformerImpl(new Properties JavaDoc(),
528         _indentNumber, this);
529     if (_uriResolver != null) {
530         result.setURIResolver(_uriResolver);
531     }
532     return result;
533     }
534
535     /**
536      * javax.xml.transform.sax.TransformerFactory implementation.
537      * Process the Source into a Templates object, which is a a compiled
538      * representation of the source. Note that this method should not be
539      * used with XSLTC, as the time-consuming compilation is done for each
540      * and every transformation.
541      *
542      * @return A Templates object that can be used to create Transformers.
543      * @throws TransformerConfigurationException
544      */

545     public Transformer JavaDoc newTransformer(Source JavaDoc source) throws
546     TransformerConfigurationException JavaDoc
547     {
548     final Templates JavaDoc templates = newTemplates(source);
549     final Transformer JavaDoc transformer = templates.newTransformer();
550     if (_uriResolver != null) {
551         transformer.setURIResolver(_uriResolver);
552     }
553     return(transformer);
554     }
555
556     /**
557      * Pass warning messages from the compiler to the error listener
558      */

559     private void passWarningsToListener(Vector JavaDoc messages)
560     throws TransformerException JavaDoc
561     {
562     if (_errorListener == null || messages == null) {
563         return;
564     }
565     // Pass messages to listener, one by one
566
final int count = messages.size();
567     for (int pos = 0; pos < count; pos++) {
568         String JavaDoc message = messages.elementAt(pos).toString();
569         _errorListener.error(
570         new TransformerConfigurationException JavaDoc(message));
571     }
572     }
573
574     /**
575      * Pass error messages from the compiler to the error listener
576      */

577     private void passErrorsToListener(Vector JavaDoc messages) {
578     try {
579         if (_errorListener == null || messages == null) {
580         return;
581         }
582         // Pass messages to listener, one by one
583
final int count = messages.size();
584         for (int pos = 0; pos < count; pos++) {
585         String JavaDoc message = messages.elementAt(pos).toString();
586         _errorListener.error(new TransformerException JavaDoc(message));
587         }
588     }
589     catch (TransformerException JavaDoc e) {
590         // nada
591
}
592     }
593
594     /**
595      * javax.xml.transform.sax.TransformerFactory implementation.
596      * Process the Source into a Templates object, which is a a compiled
597      * representation of the source.
598      *
599      * @param stylesheet The input stylesheet - DOMSource not supported!!!
600      * @return A Templates object that can be used to create Transformers.
601      * @throws TransformerConfigurationException
602      */

603     public Templates JavaDoc newTemplates(Source JavaDoc source)
604     throws TransformerConfigurationException JavaDoc
605     {
606     // If the _useClasspath attribute is true, try to load the translet from
607
// the CLASSPATH and create a template object using the loaded
608
// translet.
609
if (_useClasspath) {
610         String JavaDoc transletName = getTransletBaseName(source);
611                 
612         if (_packageName != null)
613             transletName = _packageName + "." + transletName;
614             
615         try {
616                 final Class JavaDoc clazz = ObjectFactory.findProviderClass(
617                     transletName, ObjectFactory.findClassLoader(), true);
618             resetTransientAttributes();
619                 
620             return new TemplatesImpl(new Class JavaDoc[]{clazz}, transletName, null, _indentNumber, this);
621         }
622         catch (ClassNotFoundException JavaDoc cnfe) {
623             ErrorMsg err = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, transletName);
624             throw new TransformerConfigurationException JavaDoc(err.toString());
625         }
626         catch (Exception JavaDoc e) {
627             ErrorMsg err = new ErrorMsg(
628                                      new ErrorMsg(ErrorMsg.RUNTIME_ERROR_KEY)
629                                      + e.getMessage());
630             throw new TransformerConfigurationException JavaDoc(err.toString());
631         }
632     }
633     
634     // If _autoTranslet is true, we will try to load the bytecodes
635
// from the translet classes without compiling the stylesheet.
636
if (_autoTranslet) {
637         byte[][] bytecodes = null;
638         String JavaDoc transletClassName = getTransletBaseName(source);
639         
640         if (_packageName != null)
641             transletClassName = _packageName + "." + transletClassName;
642         
643         if (_jarFileName != null)
644             bytecodes = getBytecodesFromJar(source, transletClassName);
645         else
646             bytecodes = getBytecodesFromClasses(source, transletClassName);
647       
648         if (bytecodes != null) {
649             if (_debug) {
650                 if (_jarFileName != null)
651                 System.err.println(new ErrorMsg(
652                         ErrorMsg.TRANSFORM_WITH_JAR_STR, transletClassName, _jarFileName));
653                 else
654                     System.err.println(new ErrorMsg(
655                         ErrorMsg.TRANSFORM_WITH_TRANSLET_STR, transletClassName));
656             }
657
658             // Reset the per-session attributes to their default values
659
// after each newTemplates() call.
660
resetTransientAttributes();
661         
662             return new TemplatesImpl(bytecodes, transletClassName, null, _indentNumber, this);
663         }
664     }
665     
666     // Create and initialize a stylesheet compiler
667
final XSLTC xsltc = new XSLTC();
668     if (_debug) xsltc.setDebug(true);
669     if (_enableInlining) xsltc.setTemplateInlining(true);
670     xsltc.init();
671
672     // Set a document loader (for xsl:include/import) if defined
673
if (_uriResolver != null) {
674         xsltc.setSourceLoader(this);
675     }
676
677     // Pass parameters to the Parser to make sure it locates the correct
678
// <?xml-stylesheet ...?> PI in an XML input document
679
if ((_piParams != null) && (_piParams.get(source) != null)) {
680         // Get the parameters for this Source object
681
PIParamWrapper p = (PIParamWrapper)_piParams.get(source);
682         // Pass them on to the compiler (which will pass then to the parser)
683
if (p != null) {
684         xsltc.setPIParameters(p._media, p._title, p._charset);
685         }
686     }
687
688     // Set the attributes for translet generation
689
int outputType = XSLTC.BYTEARRAY_OUTPUT;
690     if (_generateTranslet || _autoTranslet) {
691         // Set the translet name
692
xsltc.setClassName(getTransletBaseName(source));
693       
694         if (_destinationDirectory != null)
695             xsltc.setDestDirectory(_destinationDirectory);
696         else {
697             String JavaDoc xslName = getStylesheetFileName(source);
698             if (xslName != null) {
699                 File JavaDoc xslFile = new File JavaDoc(xslName);
700                 String JavaDoc xslDir = xslFile.getParent();
701         
702                 if (xslDir != null)
703                     xsltc.setDestDirectory(xslDir);
704             }
705         }
706       
707         if (_packageName != null)
708             xsltc.setPackageName(_packageName);
709     
710         if (_jarFileName != null) {
711             xsltc.setJarFileName(_jarFileName);
712             outputType = XSLTC.BYTEARRAY_AND_JAR_OUTPUT;
713         }
714         else
715             outputType = XSLTC.BYTEARRAY_AND_FILE_OUTPUT;
716     }
717
718     // Compile the stylesheet
719
final InputSource JavaDoc input = Util.getInputSource(xsltc, source);
720     byte[][] bytecodes = xsltc.compile(null, input, outputType);
721     final String JavaDoc transletName = xsltc.getClassName();
722
723     // Output to the jar file if the jar file name is set.
724
if ((_generateTranslet || _autoTranslet)
725         && bytecodes != null && _jarFileName != null) {
726         try {
727             xsltc.outputToJar();
728         }
729         catch (java.io.IOException JavaDoc e) { }
730     }
731
732     // Reset the per-session attributes to their default values
733
// after each newTemplates() call.
734
resetTransientAttributes();
735
736     // Pass compiler warnings to the error listener
737
if (_errorListener != this) {
738         try {
739         passWarningsToListener(xsltc.getWarnings());
740         }
741         catch (TransformerException JavaDoc e) {
742         throw new TransformerConfigurationException JavaDoc(e);
743         }
744     }
745     else {
746         xsltc.printWarnings();
747     }
748
749     // Check that the transformation went well before returning
750
if (bytecodes == null) {
751         
752         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_COMPILE_ERR);
753         TransformerConfigurationException JavaDoc exc = new TransformerConfigurationException JavaDoc(err.toString());
754         
755         // Pass compiler errors to the error listener
756
if (_errorListener != null) {
757             passErrorsToListener(xsltc.getErrors());
758             
759             // As required by TCK 1.2, send a fatalError to the
760
// error listener because compilation of the stylesheet
761
// failed and no further processing will be possible.
762
try {
763                 _errorListener.fatalError(exc);
764             } catch (TransformerException JavaDoc te) {
765                 // well, we tried.
766
}
767         }
768         else {
769             xsltc.printErrors();
770         }
771         throw exc;
772     }
773
774     return new TemplatesImpl(bytecodes, transletName,
775         xsltc.getOutputProperties(), _indentNumber, this);
776     }
777
778     /**
779      * javax.xml.transform.sax.SAXTransformerFactory implementation.
780      * Get a TemplatesHandler object that can process SAX ContentHandler
781      * events into a Templates object.
782      *
783      * @return A TemplatesHandler object that can handle SAX events
784      * @throws TransformerConfigurationException
785      */

786     public TemplatesHandler JavaDoc newTemplatesHandler()
787     throws TransformerConfigurationException JavaDoc
788     {
789     final TemplatesHandlerImpl handler =
790         new TemplatesHandlerImpl(_indentNumber, this);
791     if (_uriResolver != null) {
792         handler.setURIResolver(_uriResolver);
793     }
794     return handler;
795     }
796
797     /**
798      * javax.xml.transform.sax.SAXTransformerFactory implementation.
799      * Get a TransformerHandler object that can process SAX ContentHandler
800      * events into a Result. This method will return a pure copy transformer.
801      *
802      * @return A TransformerHandler object that can handle SAX events
803      * @throws TransformerConfigurationException
804      */

805     public TransformerHandler JavaDoc newTransformerHandler()
806     throws TransformerConfigurationException JavaDoc
807     {
808     final Transformer JavaDoc transformer = newTransformer();
809     if (_uriResolver != null) {
810         transformer.setURIResolver(_uriResolver);
811     }
812     return new TransformerHandlerImpl((TransformerImpl) transformer);
813     }
814
815     /**
816      * javax.xml.transform.sax.SAXTransformerFactory implementation.
817      * Get a TransformerHandler object that can process SAX ContentHandler
818      * events into a Result, based on the transformation instructions
819      * specified by the argument.
820      *
821      * @param src The source of the transformation instructions.
822      * @return A TransformerHandler object that can handle SAX events
823      * @throws TransformerConfigurationException
824      */

825     public TransformerHandler JavaDoc newTransformerHandler(Source JavaDoc src)
826     throws TransformerConfigurationException JavaDoc
827     {
828     final Transformer JavaDoc transformer = newTransformer(src);
829     if (_uriResolver != null) {
830         transformer.setURIResolver(_uriResolver);
831     }
832     return new TransformerHandlerImpl((TransformerImpl) transformer);
833     }
834
835     /**
836      * javax.xml.transform.sax.SAXTransformerFactory implementation.
837      * Get a TransformerHandler object that can process SAX ContentHandler
838      * events into a Result, based on the transformation instructions
839      * specified by the argument.
840      *
841      * @param templates Represents a pre-processed stylesheet
842      * @return A TransformerHandler object that can handle SAX events
843      * @throws TransformerConfigurationException
844      */

845     public TransformerHandler JavaDoc newTransformerHandler(Templates JavaDoc templates)
846     throws TransformerConfigurationException JavaDoc
847     {
848     final Transformer JavaDoc transformer = templates.newTransformer();
849     final TransformerImpl internal = (TransformerImpl)transformer;
850     return new TransformerHandlerImpl(internal);
851     }
852
853     /**
854      * javax.xml.transform.sax.SAXTransformerFactory implementation.
855      * Create an XMLFilter that uses the given source as the
856      * transformation instructions.
857      *
858      * @param src The source of the transformation instructions.
859      * @return An XMLFilter object, or null if this feature is not supported.
860      * @throws TransformerConfigurationException
861      */

862     public XMLFilter JavaDoc newXMLFilter(Source JavaDoc src)
863     throws TransformerConfigurationException JavaDoc
864     {
865     Templates JavaDoc templates = newTemplates(src);
866     if (templates == null) return null;
867     return newXMLFilter(templates);
868     }
869
870     /**
871      * javax.xml.transform.sax.SAXTransformerFactory implementation.
872      * Create an XMLFilter that uses the given source as the
873      * transformation instructions.
874      *
875      * @param src The source of the transformation instructions.
876      * @return An XMLFilter object, or null if this feature is not supported.
877      * @throws TransformerConfigurationException
878      */

879     public XMLFilter JavaDoc newXMLFilter(Templates JavaDoc templates)
880     throws TransformerConfigurationException JavaDoc
881     {
882     try {
883             return new org.apache.xalan.xsltc.trax.TrAXFilter(templates);
884         }
885     catch (TransformerConfigurationException JavaDoc e1) {
886             if (_errorListener != null) {
887                 try {
888                 _errorListener.fatalError(e1);
889                 return null;
890             }
891         catch (TransformerException JavaDoc e2) {
892                 new TransformerConfigurationException JavaDoc(e2);
893             }
894             }
895             throw e1;
896         }
897     }
898
899     /**
900      * Receive notification of a recoverable error.
901      * The transformer must continue to provide normal parsing events after
902      * invoking this method. It should still be possible for the application
903      * to process the document through to the end.
904      *
905      * @param exception The warning information encapsulated in a transformer
906      * exception.
907      * @throws TransformerException if the application chooses to discontinue
908      * the transformation (always does in our case).
909      */

910     public void error(TransformerException JavaDoc e)
911     throws TransformerException JavaDoc
912     {
913     Throwable JavaDoc wrapped = e.getException();
914         if (wrapped != null) {
915             System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG,
916                                             e.getMessageAndLocation(),
917                                             wrapped.getMessage()));
918         } else {
919             System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG,
920                                             e.getMessageAndLocation()));
921     }
922     throw e;
923     }
924
925     /**
926      * Receive notification of a non-recoverable error.
927      * The application must assume that the transformation cannot continue
928      * after the Transformer has invoked this method, and should continue
929      * (if at all) only to collect addition error messages. In fact,
930      * Transformers are free to stop reporting events once this method has
931      * been invoked.
932      *
933      * @param exception The warning information encapsulated in a transformer
934      * exception.
935      * @throws TransformerException if the application chooses to discontinue
936      * the transformation (always does in our case).
937      */

938     public void fatalError(TransformerException JavaDoc e)
939     throws TransformerException JavaDoc
940     {
941     Throwable JavaDoc wrapped = e.getException();
942         if (wrapped != null) {
943             System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG,
944                                             e.getMessageAndLocation(),
945                                             wrapped.getMessage()));
946         } else {
947             System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG,
948                                             e.getMessageAndLocation()));
949         }
950     throw e;
951     }
952
953     /**
954      * Receive notification of a warning.
955      * Transformers can use this method to report conditions that are not
956      * errors or fatal errors. The default behaviour is to take no action.
957      * After invoking this method, the Transformer must continue with the
958      * transformation. It should still be possible for the application to
959      * process the document through to the end.
960      *
961      * @param exception The warning information encapsulated in a transformer
962      * exception.
963      * @throws TransformerException if the application chooses to discontinue
964      * the transformation (never does in our case).
965      */

966     public void warning(TransformerException JavaDoc e)
967     throws TransformerException JavaDoc
968     {
969     Throwable JavaDoc wrapped = e.getException();
970     if (wrapped != null) {
971             System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG,
972                                             e.getMessageAndLocation(),
973                                             wrapped.getMessage()));
974     } else {
975             System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG,
976                                             e.getMessageAndLocation()));
977         }
978     }
979
980     /**
981      * This method implements XSLTC's SourceLoader interface. It is used to
982      * glue a TrAX URIResolver to the XSLTC compiler's Input and Import classes.
983      *
984      * @param href The URI of the document to load
985      * @param context The URI of the currently loaded document
986      * @param xsltc The compiler that resuests the document
987      * @return An InputSource with the loaded document
988      */

989     public InputSource JavaDoc loadSource(String JavaDoc href, String JavaDoc context, XSLTC xsltc) {
990     try {
991         if (_uriResolver != null) {
992         final Source JavaDoc source = _uriResolver.resolve(href, context);
993         if (source != null) {
994             return Util.getInputSource(xsltc, source);
995         }
996         }
997     }
998     catch (TransformerException JavaDoc e) {
999         // Falls through
1000
}
1001    return null;
1002    }
1003
1004    /**
1005     * Reset the per-session attributes to their default values
1006     */

1007    private void resetTransientAttributes() {
1008    _transletName = DEFAULT_TRANSLET_NAME;
1009    _destinationDirectory = null;
1010    _packageName = null;
1011    _jarFileName = null;
1012    }
1013        
1014    /**
1015     * Load the translet classes from local .class files and return
1016     * the bytecode array.
1017     *
1018     * @param source The xsl source
1019     * @param fullClassName The full name of the translet
1020     * @return The bytecode array
1021     */

1022    private byte[][] getBytecodesFromClasses(Source JavaDoc source, String JavaDoc fullClassName)
1023    {
1024        if (fullClassName == null)
1025            return null;
1026          
1027        String JavaDoc xslFileName = getStylesheetFileName(source);
1028        File JavaDoc xslFile = null;
1029        if (xslFileName != null)
1030            xslFile = new File JavaDoc(xslFileName);
1031        
1032        // Find the base name of the translet
1033
final String JavaDoc transletName;
1034        int lastDotIndex = fullClassName.lastIndexOf('.');
1035        if (lastDotIndex > 0)
1036            transletName = fullClassName.substring(lastDotIndex+1);
1037        else
1038            transletName = fullClassName;
1039                
1040        // Construct the path name for the translet class file
1041
String JavaDoc transletPath = fullClassName.replace('.', '/');
1042        if (_destinationDirectory != null) {
1043            transletPath = _destinationDirectory + "/" + transletPath + ".class";
1044        }
1045        else {
1046            if (xslFile != null && xslFile.getParent() != null)
1047                transletPath = xslFile.getParent() + "/" + transletPath + ".class";
1048            else
1049                transletPath = transletPath + ".class";
1050        }
1051                        
1052        // Return null if the translet class file does not exist.
1053
File JavaDoc transletFile = new File JavaDoc(transletPath);
1054        if (!transletFile.exists())
1055            return null;
1056                  
1057        // Compare the timestamps of the translet and the xsl file.
1058
// If the translet is older than the xsl file, return null
1059
// so that the xsl file is used for the transformation and
1060
// the translet is regenerated.
1061
if (xslFile != null && xslFile.exists()) {
1062            long xslTimestamp = xslFile.lastModified();
1063            long transletTimestamp = transletFile.lastModified();
1064            if (transletTimestamp < xslTimestamp)
1065                return null;
1066        }
1067        
1068        // Load the translet into a bytecode array.
1069
Vector JavaDoc bytecodes = new Vector JavaDoc();
1070        int fileLength = (int)transletFile.length();
1071        if (fileLength > 0) {
1072            FileInputStream JavaDoc input = null;
1073            try {
1074                input = new FileInputStream JavaDoc(transletFile);
1075            }
1076            catch (FileNotFoundException JavaDoc e) {
1077                return null;
1078            }
1079          
1080            byte[] bytes = new byte[fileLength];
1081            try {
1082            readFromInputStream(bytes, input, fileLength);
1083            input.close();
1084        }
1085        catch (IOException JavaDoc e) {
1086                return null;
1087            }
1088          
1089            bytecodes.addElement(bytes);
1090        }
1091        else
1092            return null;
1093        
1094        // Find the parent directory of the translet.
1095
String JavaDoc transletParentDir = transletFile.getParent();
1096        if (transletParentDir == null)
1097            transletParentDir = System.getProperty("user.dir");
1098          
1099        File JavaDoc transletParentFile = new File JavaDoc(transletParentDir);
1100        
1101        // Find all the auxiliary files which have a name pattern of "transletClass$nnn.class".
1102
final String JavaDoc transletAuxPrefix = transletName + "$";
1103        File JavaDoc[] auxfiles = transletParentFile.listFiles(new FilenameFilter JavaDoc() {
1104            public boolean accept(File JavaDoc dir, String JavaDoc name)
1105            {
1106                return (name.endsWith(".class") && name.startsWith(transletAuxPrefix));
1107            }
1108              });
1109        
1110        // Load the auxiliary class files and add them to the bytecode array.
1111
for (int i = 0; i < auxfiles.length; i++)
1112        {
1113            File JavaDoc auxfile = auxfiles[i];
1114            int auxlength = (int)auxfile.length();
1115            if (auxlength > 0) {
1116                FileInputStream JavaDoc auxinput = null;
1117                try {
1118                    auxinput = new FileInputStream JavaDoc(auxfile);
1119                }
1120                catch (FileNotFoundException JavaDoc e) {
1121                    continue;
1122                }
1123          
1124                byte[] bytes = new byte[auxlength];
1125            
1126                try {
1127                    readFromInputStream(bytes, auxinput, auxlength);
1128                    auxinput.close();
1129                }
1130                catch (IOException JavaDoc e) {
1131                    continue;
1132                }
1133            
1134                bytecodes.addElement(bytes);
1135            }
1136        }
1137        
1138        // Convert the Vector of byte[] to byte[][].
1139
final int count = bytecodes.size();
1140        if ( count > 0) {
1141            final byte[][] result = new byte[count][1];
1142            for (int i = 0; i < count; i++) {
1143                result[i] = (byte[])bytecodes.elementAt(i);
1144            }
1145          
1146            return result;
1147        }
1148        else
1149            return null;
1150    }
1151    
1152    /**
1153     * Load the translet classes from the jar file and return the bytecode.
1154     *
1155     * @param source The xsl source
1156     * @param fullClassName The full name of the translet
1157     * @return The bytecode array
1158     */

1159    private byte[][] getBytecodesFromJar(Source JavaDoc source, String JavaDoc fullClassName)
1160    {
1161        String JavaDoc xslFileName = getStylesheetFileName(source);
1162        File JavaDoc xslFile = null;
1163        if (xslFileName != null)
1164            xslFile = new File JavaDoc(xslFileName);
1165      
1166        // Construct the path for the jar file
1167
String JavaDoc jarPath = null;
1168        if (_destinationDirectory != null)
1169            jarPath = _destinationDirectory + "/" + _jarFileName;
1170        else {
1171            if (xslFile != null && xslFile.getParent() != null)
1172                jarPath = xslFile.getParent() + "/" + _jarFileName;
1173            else
1174                jarPath = _jarFileName;
1175        }
1176            
1177        // Return null if the jar file does not exist.
1178
File JavaDoc file = new File JavaDoc(jarPath);
1179        if (!file.exists())
1180            return null;
1181
1182        // Compare the timestamps of the jar file and the xsl file. Return null
1183
// if the xsl file is newer than the jar file.
1184
if (xslFile != null && xslFile.exists()) {
1185            long xslTimestamp = xslFile.lastModified();
1186            long transletTimestamp = file.lastModified();
1187            if (transletTimestamp < xslTimestamp)
1188                return null;
1189        }
1190      
1191        // Create a ZipFile object for the jar file
1192
ZipFile JavaDoc jarFile = null;
1193        try {
1194            jarFile = new ZipFile JavaDoc(file);
1195        }
1196        catch (IOException JavaDoc e) {
1197            return null;
1198        }
1199      
1200        String JavaDoc transletPath = fullClassName.replace('.', '/');
1201        String JavaDoc transletAuxPrefix = transletPath + "$";
1202        String JavaDoc transletFullName = transletPath + ".class";
1203      
1204        Vector JavaDoc bytecodes = new Vector JavaDoc();
1205      
1206        // Iterate through all entries in the jar file to find the
1207
// translet and auxiliary classes.
1208
Enumeration JavaDoc entries = jarFile.entries();
1209        while (entries.hasMoreElements())
1210        {
1211            ZipEntry JavaDoc entry = (ZipEntry JavaDoc)entries.nextElement();
1212            String JavaDoc entryName = entry.getName();
1213            if (entry.getSize() > 0 &&
1214                  (entryName.equals(transletFullName) ||
1215                  (entryName.endsWith(".class") &&
1216                      entryName.startsWith(transletAuxPrefix))))
1217            {
1218                try {
1219                    InputStream JavaDoc input = jarFile.getInputStream(entry);
1220                    int size = (int)entry.getSize();
1221                    byte[] bytes = new byte[size];
1222                    readFromInputStream(bytes, input, size);
1223                    input.close();
1224                    bytecodes.addElement(bytes);
1225                }
1226                catch (IOException JavaDoc e) {
1227                    return null;
1228                }
1229            }
1230        }
1231      
1232        // Convert the Vector of byte[] to byte[][].
1233
final int count = bytecodes.size();
1234        if (count > 0) {
1235            final byte[][] result = new byte[count][1];
1236            for (int i = 0; i < count; i++) {
1237                result[i] = (byte[])bytecodes.elementAt(i);
1238            }
1239          
1240            return result;
1241        }
1242        else
1243            return null;
1244    }
1245    
1246    /**
1247     * Read a given number of bytes from the InputStream into a byte array.
1248     *
1249     * @param bytes The byte array to store the input content.
1250     * @param input The input stream.
1251     * @param size The number of bytes to read.
1252     */

1253    private void readFromInputStream(byte[] bytes, InputStream JavaDoc input, int size)
1254        throws IOException JavaDoc
1255    {
1256      int n = 0;
1257      int offset = 0;
1258      int length = size;
1259      while (length > 0 && (n = input.read(bytes, offset, length)) > 0) {
1260          offset = offset + n;
1261          length = length - n;
1262      }
1263    }
1264
1265    /**
1266     * Return the base class name of the translet.
1267     * The translet name is resolved using the following rules:
1268     * 1. if the _transletName attribute is set and its value is not "GregorSamsa",
1269     * then _transletName is returned.
1270     * 2. otherwise get the translet name from the base name of the system ID
1271     * 3. return "GregorSamsa" if the result from step 2 is null.
1272     *
1273     * @param source The input Source
1274     * @return The name of the translet class
1275     */

1276    private String JavaDoc getTransletBaseName(Source JavaDoc source)
1277    {
1278        String JavaDoc transletBaseName = null;
1279        if (!_transletName.equals(DEFAULT_TRANSLET_NAME))
1280            return _transletName;
1281        else {
1282            String JavaDoc systemId = source.getSystemId();
1283            if (systemId != null) {
1284            String JavaDoc baseName = Util.baseName(systemId);
1285        if (baseName != null) {
1286            baseName = Util.noExtName(baseName);
1287            transletBaseName = Util.toJavaName(baseName);
1288        }
1289            }
1290        }
1291      
1292        return (transletBaseName != null) ? transletBaseName : DEFAULT_TRANSLET_NAME;
1293    }
1294        
1295    /**
1296     * Return the local file name from the systemId of the Source object
1297     *
1298     * @param source The Source
1299     * @return The file name in the local filesystem, or null if the
1300     * systemId does not represent a local file.
1301     */

1302    private String JavaDoc getStylesheetFileName(Source JavaDoc source)
1303    {
1304        String JavaDoc systemId = source.getSystemId();
1305        if (systemId != null) {
1306            File JavaDoc file = new File JavaDoc(systemId);
1307            if (file.exists())
1308                return systemId;
1309            else {
1310                URL JavaDoc url = null;
1311            try {
1312                    url = new URL JavaDoc(systemId);
1313            }
1314            catch (MalformedURLException JavaDoc e) {
1315                    return null;
1316            }
1317          
1318            if ("file".equals(url.getProtocol()))
1319                    return url.getFile();
1320            else
1321                    return null;
1322            }
1323        }
1324        else
1325            return null;
1326    }
1327
1328    /**
1329     * Returns the Class object the provides the XSLTC DTM Manager service.
1330     */

1331    protected Class JavaDoc getDTMManagerClass() {
1332        return m_DTMManagerClass;
1333    }
1334}
1335
Popular Tags