View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: TransformerFactoryImpl.java,v 1.8 2007/04/09 21:30:41 joehw Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.trax;
25  
26  import com.sun.org.apache.xalan.internal.XalanConstants;
27  import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
28  import com.sun.org.apache.xalan.internal.utils.FeatureManager;
29  import com.sun.org.apache.xalan.internal.utils.FeaturePropertyBase;
30  import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
31  import com.sun.org.apache.xalan.internal.utils.SecuritySupport;
32  import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager;
33  import com.sun.org.apache.xalan.internal.utils.XMLSecurityPropertyManager;
34  import com.sun.org.apache.xalan.internal.utils.XMLSecurityPropertyManager.Property;
35  import com.sun.org.apache.xalan.internal.utils.FeaturePropertyBase.State;
36  import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
37  import com.sun.org.apache.xalan.internal.xsltc.compiler.SourceLoader;
38  import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC;
39  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
40  import com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager;
41  import com.sun.org.apache.xml.internal.utils.StopParseException;
42  import com.sun.org.apache.xml.internal.utils.StylesheetPIHandler;
43  import java.io.File;
44  import java.io.FileInputStream;
45  import java.io.FileNotFoundException;
46  import java.io.FilenameFilter;
47  import java.io.IOException;
48  import java.io.InputStream;
49  import java.net.MalformedURLException;
50  import java.net.URL;
51  import java.util.Enumeration;
52  import java.util.Hashtable;
53  import java.util.Properties;
54  import java.util.Vector;
55  import java.util.zip.ZipEntry;
56  import java.util.zip.ZipFile;
57  import javax.xml.XMLConstants;
58  import javax.xml.parsers.SAXParser;
59  import javax.xml.parsers.SAXParserFactory;
60  
61  import javax.xml.transform.ErrorListener;
62  import javax.xml.transform.Source;
63  import javax.xml.transform.Templates;
64  import javax.xml.transform.Transformer;
65  import javax.xml.transform.TransformerConfigurationException;
66  import javax.xml.transform.TransformerException;
67  import javax.xml.transform.TransformerFactory;
68  import javax.xml.transform.URIResolver;
69  import javax.xml.transform.dom.DOMResult;
70  import javax.xml.transform.dom.DOMSource;
71  import javax.xml.transform.sax.SAXResult;
72  import javax.xml.transform.sax.SAXSource;
73  import javax.xml.transform.sax.SAXTransformerFactory;
74  import javax.xml.transform.sax.TemplatesHandler;
75  import javax.xml.transform.sax.TransformerHandler;
76  import javax.xml.transform.stax.*;
77  import javax.xml.transform.stream.StreamResult;
78  import javax.xml.transform.stream.StreamSource;
79  import org.xml.sax.InputSource;
80  import org.xml.sax.XMLFilter;
81  import org.xml.sax.XMLReader;
82  import org.xml.sax.helpers.XMLReaderFactory;
83  
84  /**
85   * Implementation of a JAXP1.1 TransformerFactory for Translets.
86   * @author G. Todd Miller
87   * @author Morten Jorgensen
88   * @author Santiago Pericas-Geertsen
89   */
90  public class TransformerFactoryImpl
91      extends SAXTransformerFactory implements SourceLoader, ErrorListener
92  {
93      // Public constants for attributes supported by the XSLTC TransformerFactory.
94      public final static String TRANSLET_NAME = "translet-name";
95      public final static String DESTINATION_DIRECTORY = "destination-directory";
96      public final static String PACKAGE_NAME = "package-name";
97      public final static String JAR_NAME = "jar-name";
98      public final static String GENERATE_TRANSLET = "generate-translet";
99      public final static String AUTO_TRANSLET = "auto-translet";
100     public final static String USE_CLASSPATH = "use-classpath";
101     public final static String DEBUG = "debug";
102     public final static String ENABLE_INLINING = "enable-inlining";
103     public final static String INDENT_NUMBER = "indent-number";
104 
105     /**
106      * This error listener is used only for this factory and is not passed to
107      * the Templates or Transformer objects that we create.
108      */
109     private ErrorListener _errorListener = this;
110 
111     /**
112      * This URIResolver is passed to all created Templates and Transformers
113      */
114     private URIResolver _uriResolver = null;
115 
116     /**
117      * As Gregor Samsa awoke one morning from uneasy dreams he found himself
118      * transformed in his bed into a gigantic insect. He was lying on his hard,
119      * as it were armour plated, back, and if he lifted his head a little he
120      * could see his big, brown belly divided into stiff, arched segments, on
121      * top of which the bed quilt could hardly keep in position and was about
122      * to slide off completely. His numerous legs, which were pitifully thin
123      * compared to the rest of his bulk, waved helplessly before his eyes.
124      * "What has happened to me?", he thought. It was no dream....
125      */
126     protected final static String DEFAULT_TRANSLET_NAME = "GregorSamsa";
127 
128     /**
129      * The class name of the translet
130      */
131     private String _transletName = DEFAULT_TRANSLET_NAME;
132 
133     /**
134      * The destination directory for the translet
135      */
136     private String _destinationDirectory = null;
137 
138     /**
139      * The package name prefix for all generated translet classes
140      */
141     private String _packageName = null;
142 
143     /**
144      * The jar file name which the translet classes are packaged into
145      */
146     private String _jarFileName = null;
147 
148     /**
149      * This Hashtable is used to store parameters for locating
150      * <?xml-stylesheet ...?> processing instructions in XML docs.
151      */
152     private Hashtable _piParams = null;
153 
154     /**
155      * The above hashtable stores objects of this class.
156      */
157     private static class PIParamWrapper {
158         public String _media = null;
159         public String _title = null;
160         public String _charset = null;
161 
162         public PIParamWrapper(String media, String title, String charset) {
163             _media = media;
164             _title = title;
165             _charset = charset;
166         }
167     }
168 
169     /**
170      * Set to <code>true</code> when debugging is enabled.
171      */
172     private boolean _debug = false;
173 
174     /**
175      * Set to <code>true</code> when templates are inlined.
176      */
177     private boolean _enableInlining = false;
178 
179     /**
180      * Set to <code>true</code> when we want to generate
181      * translet classes from the stylesheet.
182      */
183     private boolean _generateTranslet = false;
184 
185     /**
186      * If this is set to <code>true</code>, we attempt to use translet classes
187      * for transformation if possible without compiling the stylesheet. The
188      * translet class is only used if its timestamp is newer than the timestamp
189      * of the stylesheet.
190      */
191     private boolean _autoTranslet = false;
192 
193     /**
194      * If this is set to <code>true</code>, we attempt to load the translet
195      * from the CLASSPATH.
196      */
197     private boolean _useClasspath = false;
198 
199     /**
200      * Number of indent spaces when indentation is turned on.
201      */
202     private int _indentNumber = -1;
203 
204     /**
205      * <p>State of secure processing feature.</p>
206      */
207     private boolean _isNotSecureProcessing = true;
208     /**
209      * <p>State of secure mode.</p>
210      */
211     private boolean _isSecureMode = false;
212 
213     /**
214      * Indicates whether implementation parts should use
215      *   service loader (or similar).
216      * Note the default value (false) is the safe option..
217      */
218     private boolean _useServicesMechanism;
219 
220     /**
221      * protocols allowed for external references set by the stylesheet processing instruction, Import and Include element.
222      */
223     private String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
224      /**
225      * protocols allowed for external DTD references in source file and/or stylesheet.
226      */
227     private String _accessExternalDTD = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
228 
229     private XMLSecurityPropertyManager _xmlSecurityPropertyMgr;
230     private XMLSecurityManager _xmlSecurityManager;
231 
232     private final FeatureManager _featureManager;
233 
234     /**
235      * javax.xml.transform.sax.TransformerFactory implementation.
236      */
237     public TransformerFactoryImpl() {
238         this(true);
239     }
240 
241     public static TransformerFactory newTransformerFactoryNoServiceLoader() {
242         return new TransformerFactoryImpl(false);
243     }
244 
245     private TransformerFactoryImpl(boolean useServicesMechanism) {
246         this._useServicesMechanism = useServicesMechanism;
247         _featureManager = new FeatureManager();
248 
249         if (System.getSecurityManager() != null) {
250             _isSecureMode = true;
251             _isNotSecureProcessing = false;
252             _featureManager.setValue(FeatureManager.Feature.ORACLE_ENABLE_EXTENSION_FUNCTION,
253                     FeaturePropertyBase.State.FSP, XalanConstants.FEATURE_FALSE);
254         }
255 
256         _xmlSecurityPropertyMgr = new XMLSecurityPropertyManager();
257         _accessExternalDTD = _xmlSecurityPropertyMgr.getValue(
258                 Property.ACCESS_EXTERNAL_DTD);
259         _accessExternalStylesheet = _xmlSecurityPropertyMgr.getValue(
260                 Property.ACCESS_EXTERNAL_STYLESHEET);
261 
262         //Parser's security manager
263         _xmlSecurityManager = new XMLSecurityManager(true);
264     }
265 
266     /**
267      * javax.xml.transform.sax.TransformerFactory implementation.
268      * Set the error event listener for the TransformerFactory, which is used
269      * for the processing of transformation instructions, and not for the
270      * transformation itself.
271      *
272      * @param listener The error listener to use with the TransformerFactory
273      * @throws IllegalArgumentException
274      */
275     @Override
276     public void setErrorListener(ErrorListener listener)
277         throws IllegalArgumentException
278     {
279         if (listener == null) {
280             ErrorMsg err = new ErrorMsg(ErrorMsg.ERROR_LISTENER_NULL_ERR,
281                                         "TransformerFactory");
282             throw new IllegalArgumentException(err.toString());
283         }
284         _errorListener = listener;
285     }
286 
287     /**
288      * javax.xml.transform.sax.TransformerFactory implementation.
289      * Get the error event handler for the TransformerFactory.
290      *
291      * @return The error listener used with the TransformerFactory
292      */
293     @Override
294     public ErrorListener getErrorListener() {
295         return _errorListener;
296     }
297 
298     /**
299      * javax.xml.transform.sax.TransformerFactory implementation.
300      * Returns the value set for a TransformerFactory attribute
301      *
302      * @param name The attribute name
303      * @return An object representing the attribute value
304      * @throws IllegalArgumentException
305      */
306     @Override
307     public Object getAttribute(String name)
308         throws IllegalArgumentException
309     {
310         // Return value for attribute 'translet-name'
311         if (name.equals(TRANSLET_NAME)) {
312             return _transletName;
313         }
314         else if (name.equals(GENERATE_TRANSLET)) {
315             return new Boolean(_generateTranslet);
316         }
317         else if (name.equals(AUTO_TRANSLET)) {
318             return new Boolean(_autoTranslet);
319         }
320         else if (name.equals(ENABLE_INLINING)) {
321             if (_enableInlining)
322               return Boolean.TRUE;
323             else
324               return Boolean.FALSE;
325         } else if (name.equals(XalanConstants.SECURITY_MANAGER)) {
326             return _xmlSecurityManager;
327         }
328 
329         /** Check to see if the property is managed by the security manager **/
330         String propertyValue = (_xmlSecurityManager != null) ?
331                 _xmlSecurityManager.getLimitAsString(name) : null;
332         if (propertyValue != null) {
333             return propertyValue;
334         } else {
335             propertyValue = (_xmlSecurityPropertyMgr != null) ?
336                 _xmlSecurityPropertyMgr.getValue(name) : null;
337             if (propertyValue != null) {
338                 return propertyValue;
339             }
340         }
341 
342         // Throw an exception for all other attributes
343         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_INVALID_ATTR_ERR, name);
344         throw new IllegalArgumentException(err.toString());
345     }
346 
347     /**
348      * javax.xml.transform.sax.TransformerFactory implementation.
349      * Sets the value for a TransformerFactory attribute.
350      *
351      * @param name The attribute name
352      * @param value An object representing the attribute value
353      * @throws IllegalArgumentException
354      */
355     @Override
356     public void setAttribute(String name, Object value)
357         throws IllegalArgumentException
358     {
359         // Set the default translet name (ie. class name), which will be used
360         // for translets that cannot be given a name from their system-id.
361         if (name.equals(TRANSLET_NAME) && value instanceof String) {
362             _transletName = (String) value;
363             return;
364         }
365         else if (name.equals(DESTINATION_DIRECTORY) && value instanceof String) {
366             _destinationDirectory = (String) value;
367             return;
368         }
369         else if (name.equals(PACKAGE_NAME) && value instanceof String) {
370             _packageName = (String) value;
371             return;
372         }
373         else if (name.equals(JAR_NAME) && value instanceof String) {
374             _jarFileName = (String) value;
375             return;
376         }
377         else if (name.equals(GENERATE_TRANSLET)) {
378             if (value instanceof Boolean) {
379                 _generateTranslet = ((Boolean) value).booleanValue();
380                 return;
381             }
382             else if (value instanceof String) {
383                 _generateTranslet = ((String) value).equalsIgnoreCase("true");
384                 return;
385             }
386         }
387         else if (name.equals(AUTO_TRANSLET)) {
388             if (value instanceof Boolean) {
389                 _autoTranslet = ((Boolean) value).booleanValue();
390                 return;
391             }
392             else if (value instanceof String) {
393                 _autoTranslet = ((String) value).equalsIgnoreCase("true");
394                 return;
395             }
396         }
397         else if (name.equals(USE_CLASSPATH)) {
398             if (value instanceof Boolean) {
399                 _useClasspath = ((Boolean) value).booleanValue();
400                 return;
401             }
402             else if (value instanceof String) {
403                 _useClasspath = ((String) value).equalsIgnoreCase("true");
404                 return;
405             }
406         }
407         else if (name.equals(DEBUG)) {
408             if (value instanceof Boolean) {
409                 _debug = ((Boolean) value).booleanValue();
410                 return;
411             }
412             else if (value instanceof String) {
413                 _debug = ((String) value).equalsIgnoreCase("true");
414                 return;
415             }
416         }
417         else if (name.equals(ENABLE_INLINING)) {
418             if (value instanceof Boolean) {
419                 _enableInlining = ((Boolean) value).booleanValue();
420                 return;
421             }
422             else if (value instanceof String) {
423                 _enableInlining = ((String) value).equalsIgnoreCase("true");
424                 return;
425             }
426         }
427         else if (name.equals(INDENT_NUMBER)) {
428             if (value instanceof String) {
429                 try {
430                     _indentNumber = Integer.parseInt((String) value);
431                     return;
432                 }
433                 catch (NumberFormatException e) {
434                     // Falls through
435                 }
436             }
437             else if (value instanceof Integer) {
438                 _indentNumber = ((Integer) value).intValue();
439                 return;
440             }
441         }
442 
443         if (_xmlSecurityManager != null &&
444                 _xmlSecurityManager.setLimit(name, XMLSecurityManager.State.APIPROPERTY, value)) {
445             return;
446         }
447 
448         if (_xmlSecurityPropertyMgr != null &&
449             _xmlSecurityPropertyMgr.setValue(name, XMLSecurityPropertyManager.State.APIPROPERTY, value)) {
450             _accessExternalDTD = _xmlSecurityPropertyMgr.getValue(
451                     Property.ACCESS_EXTERNAL_DTD);
452             _accessExternalStylesheet = _xmlSecurityPropertyMgr.getValue(
453                     Property.ACCESS_EXTERNAL_STYLESHEET);
454             return;
455         }
456 
457         // Throw an exception for all other attributes
458         final ErrorMsg err
459             = new ErrorMsg(ErrorMsg.JAXP_INVALID_ATTR_ERR, name);
460         throw new IllegalArgumentException(err.toString());
461     }
462 
463     /**
464      * <p>Set a feature for this <code>TransformerFactory</code> and <code>Transformer</code>s
465      * or <code>Template</code>s created by this factory.</p>
466      *
467      * <p>
468      * Feature names are fully qualified {@link java.net.URI}s.
469      * Implementations may define their own features.
470      * An {@link TransformerConfigurationException} is thrown if this <code>TransformerFactory</code> or the
471      * <code>Transformer</code>s or <code>Template</code>s it creates cannot support the feature.
472      * It is possible for an <code>TransformerFactory</code> to expose a feature value but be unable to change its state.
473      * </p>
474      *
475      * <p>See {@link javax.xml.transform.TransformerFactory} for full documentation of specific features.</p>
476      *
477      * @param name Feature name.
478      * @param value Is feature state <code>true</code> or <code>false</code>.
479      *
480      * @throws TransformerConfigurationException if this <code>TransformerFactory</code>
481      *   or the <code>Transformer</code>s or <code>Template</code>s it creates cannot support this feature.
482      * @throws NullPointerException If the <code>name</code> parameter is null.
483      */
484     @Override
485     public void setFeature(String name, boolean value)
486         throws TransformerConfigurationException {
487 
488         // feature name cannot be null
489         if (name == null) {
490             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_SET_FEATURE_NULL_NAME);
491             throw new NullPointerException(err.toString());
492         }
493         // secure processing?
494         else if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
495             if ((_isSecureMode) && (!value)) {
496                 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_SECUREPROCESSING_FEATURE);
497                 throw new TransformerConfigurationException(err.toString());
498             }
499             _isNotSecureProcessing = !value;
500             _xmlSecurityManager.setSecureProcessing(value);
501 
502             // set external access restriction when FSP is explicitly set
503             if (value && XalanConstants.IS_JDK8_OR_ABOVE) {
504                 _xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD,
505                         State.FSP, XalanConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
506                 _xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_STYLESHEET,
507                         State.FSP, XalanConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
508                 _accessExternalDTD = _xmlSecurityPropertyMgr.getValue(
509                         Property.ACCESS_EXTERNAL_DTD);
510                 _accessExternalStylesheet = _xmlSecurityPropertyMgr.getValue(
511                         Property.ACCESS_EXTERNAL_STYLESHEET);
512             }
513 
514             if (value && _featureManager != null) {
515                 _featureManager.setValue(FeatureManager.Feature.ORACLE_ENABLE_EXTENSION_FUNCTION,
516                         FeaturePropertyBase.State.FSP, XalanConstants.FEATURE_FALSE);
517             }
518             return;
519         }
520         else if (name.equals(XalanConstants.ORACLE_FEATURE_SERVICE_MECHANISM)) {
521             //in secure mode, let _useServicesMechanism be determined by the constructor
522             if (!_isSecureMode)
523                 _useServicesMechanism = value;
524         }
525         else {
526             if (_featureManager != null &&
527                     _featureManager.setValue(name, State.APIPROPERTY, value)) {
528                 return;
529             }
530 
531             // unknown feature
532             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNSUPPORTED_FEATURE, name);
533             throw new TransformerConfigurationException(err.toString());
534         }
535     }
536 
537     /**
538      * javax.xml.transform.sax.TransformerFactory implementation.
539      * Look up the value of a feature (to see if it is supported).
540      * This method must be updated as the various methods and features of this
541      * class are implemented.
542      *
543      * @param name The feature name
544      * @return 'true' if feature is supported, 'false' if not
545      */
546     @Override
547     public boolean getFeature(String name) {
548         // All supported features should be listed here
549         String[] features = {
550             DOMSource.FEATURE,
551             DOMResult.FEATURE,
552             SAXSource.FEATURE,
553             SAXResult.FEATURE,
554             StAXSource.FEATURE,
555             StAXResult.FEATURE,
556             StreamSource.FEATURE,
557             StreamResult.FEATURE,
558             SAXTransformerFactory.FEATURE,
559             SAXTransformerFactory.FEATURE_XMLFILTER,
560             XalanConstants.ORACLE_FEATURE_SERVICE_MECHANISM
561         };
562 
563         // feature name cannot be null
564         if (name == null) {
565             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_GET_FEATURE_NULL_NAME);
566             throw new NullPointerException(err.toString());
567         }
568 
569         // Inefficient, but array is small
570         for (int i =0; i < features.length; i++) {
571             if (name.equals(features[i])) {
572                 return true;
573             }
574         }
575         // secure processing?
576         if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
577                 return !_isNotSecureProcessing;
578         }
579 
580         /** Check to see if the property is managed by the security manager **/
581         String propertyValue = (_featureManager != null) ?
582                 _featureManager.getValueAsString(name) : null;
583         if (propertyValue != null) {
584             return Boolean.parseBoolean(propertyValue);
585         }
586 
587         // Feature not supported
588         return false;
589     }
590     /**
591      * Return the state of the services mechanism feature.
592      */
593     public boolean useServicesMechnism() {
594         return _useServicesMechanism;
595     }
596 
597      /**
598      * @return the feature manager
599      */
600     public FeatureManager getFeatureManager() {
601         return _featureManager;
602     }
603 
604     /**
605      * javax.xml.transform.sax.TransformerFactory implementation.
606      * Get the object that is used by default during the transformation to
607      * resolve URIs used in document(), xsl:import, or xsl:include.
608      *
609      * @return The URLResolver used for this TransformerFactory and all
610      * Templates and Transformer objects created using this factory
611      */
612     @Override
613     public URIResolver getURIResolver() {
614         return _uriResolver;
615     }
616 
617     /**
618      * javax.xml.transform.sax.TransformerFactory implementation.
619      * Set the object that is used by default during the transformation to
620      * resolve URIs used in document(), xsl:import, or xsl:include. Note that
621      * this does not affect Templates and Transformers that are already
622      * created with this factory.
623      *
624      * @param resolver The URLResolver used for this TransformerFactory and all
625      * Templates and Transformer objects created using this factory
626      */
627     @Override
628     public void setURIResolver(URIResolver resolver) {
629         _uriResolver = resolver;
630     }
631 
632     /**
633      * javax.xml.transform.sax.TransformerFactory implementation.
634      * Get the stylesheet specification(s) associated via the xml-stylesheet
635      * processing instruction (see http://www.w3.org/TR/xml-stylesheet/) with
636      * the document document specified in the source parameter, and that match
637      * the given criteria.
638      *
639      * @param source The XML source document.
640      * @param media The media attribute to be matched. May be null, in which
641      * case the prefered templates will be used (i.e. alternate = no).
642      * @param title The value of the title attribute to match. May be null.
643      * @param charset The value of the charset attribute to match. May be null.
644      * @return A Source object suitable for passing to the TransformerFactory.
645      * @throws TransformerConfigurationException
646      */
647     @Override
648     public Source  getAssociatedStylesheet(Source source, String media,
649                                           String title, String charset)
650         throws TransformerConfigurationException {
651 
652         String baseId;
653         XMLReader reader;
654         InputSource isource;
655 
656 
657         /**
658          * Fix for bugzilla bug 24187
659          */
660         StylesheetPIHandler _stylesheetPIHandler = new StylesheetPIHandler(null,media,title,charset);
661 
662         try {
663 
664             if (source instanceof DOMSource ) {
665                 final DOMSource domsrc = (DOMSource) source;
666                 baseId = domsrc.getSystemId();
667                 final org.w3c.dom.Node node = domsrc.getNode();
668                 final DOM2SAX dom2sax = new DOM2SAX(node);
669 
670                 _stylesheetPIHandler.setBaseId(baseId);
671 
672                 dom2sax.setContentHandler( _stylesheetPIHandler);
673                 dom2sax.parse();
674             } else {
675                 isource = SAXSource.sourceToInputSource(source);
676                 baseId = isource.getSystemId();
677 
678                 SAXParserFactory factory = FactoryImpl.getSAXFactory(_useServicesMechanism);
679                 factory.setNamespaceAware(true);
680 
681                 if (!_isNotSecureProcessing) {
682                     try {
683                         factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
684                     }
685                     catch (org.xml.sax.SAXException e) {}
686                 }
687 
688                 SAXParser jaxpParser = factory.newSAXParser();
689 
690                 reader = jaxpParser.getXMLReader();
691                 if (reader == null) {
692                     reader = XMLReaderFactory.createXMLReader();
693                 }
694 
695                 _stylesheetPIHandler.setBaseId(baseId);
696                 reader.setContentHandler(_stylesheetPIHandler);
697                 reader.parse(isource);
698 
699             }
700 
701             if (_uriResolver != null ) {
702                 _stylesheetPIHandler.setURIResolver(_uriResolver);
703             }
704 
705         } catch (StopParseException e ) {
706           // startElement encountered so do not parse further
707 
708         } catch (javax.xml.parsers.ParserConfigurationException e) {
709 
710              throw new TransformerConfigurationException(
711              "getAssociatedStylesheets failed", e);
712 
713         } catch (org.xml.sax.SAXException se) {
714 
715              throw new TransformerConfigurationException(
716              "getAssociatedStylesheets failed", se);
717 
718 
719         } catch (IOException ioe ) {
720            throw new TransformerConfigurationException(
721            "getAssociatedStylesheets failed", ioe);
722 
723         }
724 
725          return _stylesheetPIHandler.getAssociatedStylesheet();
726 
727     }
728 
729     /**
730      * javax.xml.transform.sax.TransformerFactory implementation.
731      * Create a Transformer object that copies the input document to the result.
732      *
733      * @return A Transformer object that simply copies the source to the result.
734      * @throws TransformerConfigurationException
735      */
736     @Override
737     public Transformer newTransformer()
738         throws TransformerConfigurationException
739     {
740         TransformerImpl result = new TransformerImpl(new Properties(),
741             _indentNumber, this);
742         if (_uriResolver != null) {
743             result.setURIResolver(_uriResolver);
744         }
745 
746         if (!_isNotSecureProcessing) {
747             result.setSecureProcessing(true);
748         }
749         return result;
750     }
751 
752     /**
753      * javax.xml.transform.sax.TransformerFactory implementation.
754      * Process the Source into a Templates object, which is a a compiled
755      * representation of the source. Note that this method should not be
756      * used with XSLTC, as the time-consuming compilation is done for each
757      * and every transformation.
758      *
759      * @return A Templates object that can be used to create Transformers.
760      * @throws TransformerConfigurationException
761      */
762     @Override
763     public Transformer newTransformer(Source source) throws
764         TransformerConfigurationException
765     {
766         final Templates templates = newTemplates(source);
767         final Transformer transformer = templates.newTransformer();
768         if (_uriResolver != null) {
769             transformer.setURIResolver(_uriResolver);
770         }
771         return(transformer);
772     }
773 
774     /**
775      * Pass warning messages from the compiler to the error listener
776      */
777     private void passWarningsToListener(Vector messages)
778         throws TransformerException
779     {
780         if (_errorListener == null || messages == null) {
781             return;
782         }
783         // Pass messages to listener, one by one
784         final int count = messages.size();
785         for (int pos = 0; pos < count; pos++) {
786             ErrorMsg msg = (ErrorMsg)messages.elementAt(pos);
787             // Workaround for the TCK failure ErrorListener.errorTests.error001.
788             if (msg.isWarningError())
789                 _errorListener.error(
790                     new TransformerConfigurationException(msg.toString()));
791             else
792                 _errorListener.warning(
793                     new TransformerConfigurationException(msg.toString()));
794         }
795     }
796 
797     /**
798      * Pass error messages from the compiler to the error listener
799      */
800     private void passErrorsToListener(Vector messages) {
801         try {
802             if (_errorListener == null || messages == null) {
803                 return;
804             }
805             // Pass messages to listener, one by one
806             final int count = messages.size();
807             for (int pos = 0; pos < count; pos++) {
808                 String message = messages.elementAt(pos).toString();
809                 _errorListener.error(new TransformerException(message));
810             }
811         }
812         catch (TransformerException e) {
813             // nada
814         }
815     }
816 
817     /**
818      * javax.xml.transform.sax.TransformerFactory implementation.
819      * Process the Source into a Templates object, which is a a compiled
820      * representation of the source.
821      *
822      * @param source The input stylesheet - DOMSource not supported!!!
823      * @return A Templates object that can be used to create Transformers.
824      * @throws TransformerConfigurationException
825      */
826     @Override
827     public Templates newTemplates(Source source)
828         throws TransformerConfigurationException
829     {
830         // If the _useClasspath attribute is true, try to load the translet from
831         // the CLASSPATH and create a template object using the loaded
832         // translet.
833         if (_useClasspath) {
834             String transletName = getTransletBaseName(source);
835 
836             if (_packageName != null)
837                 transletName = _packageName + "." + transletName;
838 
839             try {
840                 final Class clazz = ObjectFactory.findProviderClass(transletName, true);
841                 resetTransientAttributes();
842 
843                 return new TemplatesImpl(new Class[]{clazz}, transletName, null, _indentNumber, this);
844             }
845             catch (ClassNotFoundException cnfe) {
846                 ErrorMsg err = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, transletName);
847                 throw new TransformerConfigurationException(err.toString());
848             }
849             catch (Exception e) {
850                 ErrorMsg err = new ErrorMsg(
851                                      new ErrorMsg(ErrorMsg.RUNTIME_ERROR_KEY)
852                                      + e.getMessage());
853                 throw new TransformerConfigurationException(err.toString());
854             }
855         }
856 
857         // If _autoTranslet is true, we will try to load the bytecodes
858         // from the translet classes without compiling the stylesheet.
859         if (_autoTranslet)  {
860             byte[][] bytecodes;
861             String transletClassName = getTransletBaseName(source);
862 
863             if (_packageName != null)
864                 transletClassName = _packageName + "." + transletClassName;
865 
866             if (_jarFileName != null)
867                 bytecodes = getBytecodesFromJar(source, transletClassName);
868             else
869                 bytecodes = getBytecodesFromClasses(source, transletClassName);
870 
871             if (bytecodes != null) {
872                 if (_debug) {
873                     if (_jarFileName != null)
874                         System.err.println(new ErrorMsg(
875                             ErrorMsg.TRANSFORM_WITH_JAR_STR, transletClassName, _jarFileName));
876                     else
877                         System.err.println(new ErrorMsg(
878                             ErrorMsg.TRANSFORM_WITH_TRANSLET_STR, transletClassName));
879                 }
880 
881                 // Reset the per-session attributes to their default values
882                 // after each newTemplates() call.
883                 resetTransientAttributes();
884 
885                 return new TemplatesImpl(bytecodes, transletClassName, null, _indentNumber, this);
886             }
887         }
888 
889         // Create and initialize a stylesheet compiler
890         final XSLTC xsltc = new XSLTC(_useServicesMechanism, _featureManager);
891         if (_debug) xsltc.setDebug(true);
892         if (_enableInlining)
893                 xsltc.setTemplateInlining(true);
894         else
895                 xsltc.setTemplateInlining(false);
896 
897         if (!_isNotSecureProcessing) xsltc.setSecureProcessing(true);
898         xsltc.setProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, _accessExternalStylesheet);
899         xsltc.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, _accessExternalDTD);
900         xsltc.setProperty(XalanConstants.SECURITY_MANAGER, _xmlSecurityManager);
901         xsltc.init();
902 
903         // Set a document loader (for xsl:include/import) if defined
904         if (_uriResolver != null) {
905             xsltc.setSourceLoader(this);
906         }
907 
908         // Pass parameters to the Parser to make sure it locates the correct
909         // <?xml-stylesheet ...?> PI in an XML input document
910         if ((_piParams != null) && (_piParams.get(source) != null)) {
911             // Get the parameters for this Source object
912             PIParamWrapper p = (PIParamWrapper)_piParams.get(source);
913             // Pass them on to the compiler (which will pass then to the parser)
914             if (p != null) {
915                 xsltc.setPIParameters(p._media, p._title, p._charset);
916             }
917         }
918 
919         // Set the attributes for translet generation
920         int outputType = XSLTC.BYTEARRAY_OUTPUT;
921         if (_generateTranslet || _autoTranslet) {
922             // Set the translet name
923             xsltc.setClassName(getTransletBaseName(source));
924 
925             if (_destinationDirectory != null)
926                 xsltc.setDestDirectory(_destinationDirectory);
927             else {
928                 String xslName = getStylesheetFileName(source);
929                 if (xslName != null) {
930                     File xslFile = new File(xslName);
931                     String xslDir = xslFile.getParent();
932 
933                     if (xslDir != null)
934                         xsltc.setDestDirectory(xslDir);
935                 }
936             }
937 
938             if (_packageName != null)
939                 xsltc.setPackageName(_packageName);
940 
941             if (_jarFileName != null) {
942                 xsltc.setJarFileName(_jarFileName);
943                 outputType = XSLTC.BYTEARRAY_AND_JAR_OUTPUT;
944             }
945             else
946                 outputType = XSLTC.BYTEARRAY_AND_FILE_OUTPUT;
947         }
948 
949         // Compile the stylesheet
950         final InputSource input = Util.getInputSource(xsltc, source);
951         byte[][] bytecodes = xsltc.compile(null, input, outputType);
952         final String transletName = xsltc.getClassName();
953 
954         // Output to the jar file if the jar file name is set.
955         if ((_generateTranslet || _autoTranslet)
956                 && bytecodes != null && _jarFileName != null) {
957             try {
958                 xsltc.outputToJar();
959             }
960             catch (java.io.IOException e) { }
961         }
962 
963         // Reset the per-session attributes to their default values
964         // after each newTemplates() call.
965         resetTransientAttributes();
966 
967         // Pass compiler warnings to the error listener
968         if (_errorListener != this) {
969             try {
970                 passWarningsToListener(xsltc.getWarnings());
971             }
972             catch (TransformerException e) {
973                 throw new TransformerConfigurationException(e);
974             }
975         }
976         else {
977             xsltc.printWarnings();
978         }
979 
980         // Check that the transformation went well before returning
981     if (bytecodes == null) {
982         Vector errs = xsltc.getErrors();
983         ErrorMsg err;
984         if (errs != null) {
985             err = (ErrorMsg)errs.elementAt(errs.size()-1);
986         } else {
987             err = new ErrorMsg(ErrorMsg.JAXP_COMPILE_ERR);
988         }
989         Throwable cause = err.getCause();
990         TransformerConfigurationException exc;
991         if (cause != null) {
992             exc =  new TransformerConfigurationException(cause.getMessage(), cause);
993         } else {
994             exc =  new TransformerConfigurationException(err.toString());
995         }
996 
997         // Pass compiler errors to the error listener
998         if (_errorListener != null) {
999             passErrorsToListener(xsltc.getErrors());
1000 
1001             // As required by TCK 1.2, send a fatalError to the
1002             // error listener because compilation of the stylesheet
1003             // failed and no further processing will be possible.
1004             try {
1005                 _errorListener.fatalError(exc);
1006             } catch (TransformerException te) {
1007                 // well, we tried.
1008             }
1009         }
1010         else {
1011             xsltc.printErrors();
1012         }
1013         throw exc;
1014     }
1015 
1016         return new TemplatesImpl(bytecodes, transletName,
1017             xsltc.getOutputProperties(), _indentNumber, this);
1018     }
1019 
1020     /**
1021      * javax.xml.transform.sax.SAXTransformerFactory implementation.
1022      * Get a TemplatesHandler object that can process SAX ContentHandler
1023      * events into a Templates object.
1024      *
1025      * @return A TemplatesHandler object that can handle SAX events
1026      * @throws TransformerConfigurationException
1027      */
1028     @Override
1029     public TemplatesHandler newTemplatesHandler()
1030         throws TransformerConfigurationException
1031     {
1032         final TemplatesHandlerImpl handler =
1033             new TemplatesHandlerImpl(_indentNumber, this);
1034         if (_uriResolver != null) {
1035             handler.setURIResolver(_uriResolver);
1036         }
1037         return handler;
1038     }
1039 
1040     /**
1041      * javax.xml.transform.sax.SAXTransformerFactory implementation.
1042      * Get a TransformerHandler object that can process SAX ContentHandler
1043      * events into a Result. This method will return a pure copy transformer.
1044      *
1045      * @return A TransformerHandler object that can handle SAX events
1046      * @throws TransformerConfigurationException
1047      */
1048     @Override
1049     public TransformerHandler newTransformerHandler()
1050         throws TransformerConfigurationException
1051     {
1052         final Transformer transformer = newTransformer();
1053         if (_uriResolver != null) {
1054             transformer.setURIResolver(_uriResolver);
1055         }
1056         return new TransformerHandlerImpl((TransformerImpl) transformer);
1057     }
1058 
1059     /**
1060      * javax.xml.transform.sax.SAXTransformerFactory implementation.
1061      * Get a TransformerHandler object that can process SAX ContentHandler
1062      * events into a Result, based on the transformation instructions
1063      * specified by the argument.
1064      *
1065      * @param src The source of the transformation instructions.
1066      * @return A TransformerHandler object that can handle SAX events
1067      * @throws TransformerConfigurationException
1068      */
1069     @Override
1070     public TransformerHandler newTransformerHandler(Source src)
1071         throws TransformerConfigurationException
1072     {
1073         final Transformer transformer = newTransformer(src);
1074         if (_uriResolver != null) {
1075             transformer.setURIResolver(_uriResolver);
1076         }
1077         return new TransformerHandlerImpl((TransformerImpl) transformer);
1078     }
1079 
1080     /**
1081      * javax.xml.transform.sax.SAXTransformerFactory implementation.
1082      * Get a TransformerHandler object that can process SAX ContentHandler
1083      * events into a Result, based on the transformation instructions
1084      * specified by the argument.
1085      *
1086      * @param templates Represents a pre-processed stylesheet
1087      * @return A TransformerHandler object that can handle SAX events
1088      * @throws TransformerConfigurationException
1089      */
1090     @Override
1091     public TransformerHandler newTransformerHandler(Templates templates)
1092         throws TransformerConfigurationException
1093     {
1094         final Transformer transformer = templates.newTransformer();
1095         final TransformerImpl internal = (TransformerImpl)transformer;
1096         return new TransformerHandlerImpl(internal);
1097     }
1098 
1099     /**
1100      * javax.xml.transform.sax.SAXTransformerFactory implementation.
1101      * Create an XMLFilter that uses the given source as the
1102      * transformation instructions.
1103      *
1104      * @param src The source of the transformation instructions.
1105      * @return An XMLFilter object, or null if this feature is not supported.
1106      * @throws TransformerConfigurationException
1107      */
1108     @Override
1109     public XMLFilter newXMLFilter(Source src)
1110         throws TransformerConfigurationException
1111     {
1112         Templates templates = newTemplates(src);
1113         if (templates == null) return null;
1114         return newXMLFilter(templates);
1115     }
1116 
1117     /**
1118      * javax.xml.transform.sax.SAXTransformerFactory implementation.
1119      * Create an XMLFilter that uses the given source as the
1120      * transformation instructions.
1121      *
1122      * @param templates The source of the transformation instructions.
1123      * @return An XMLFilter object, or null if this feature is not supported.
1124      * @throws TransformerConfigurationException
1125      */
1126     @Override
1127     public XMLFilter newXMLFilter(Templates templates)
1128         throws TransformerConfigurationException
1129     {
1130         try {
1131             return new com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter(templates);
1132         }
1133         catch (TransformerConfigurationException e1) {
1134             if (_errorListener != null) {
1135                 try {
1136                     _errorListener.fatalError(e1);
1137                     return null;
1138                 }
1139                 catch (TransformerException e2) {
1140                     new TransformerConfigurationException(e2);
1141                 }
1142             }
1143             throw e1;
1144         }
1145     }
1146 
1147     /**
1148      * Receive notification of a recoverable error.
1149      * The transformer must continue to provide normal parsing events after
1150      * invoking this method. It should still be possible for the application
1151      * to process the document through to the end.
1152      *
1153      * @param e The warning information encapsulated in a transformer
1154      * exception.
1155      * @throws TransformerException if the application chooses to discontinue
1156      * the transformation (always does in our case).
1157      */
1158     @Override
1159     public void error(TransformerException e)
1160         throws TransformerException
1161     {
1162         Throwable wrapped = e.getException();
1163         if (wrapped != null) {
1164             System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG,
1165                                             e.getMessageAndLocation(),
1166                                             wrapped.getMessage()));
1167         } else {
1168             System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG,
1169                                             e.getMessageAndLocation()));
1170         }
1171         throw e;
1172     }
1173 
1174     /**
1175      * Receive notification of a non-recoverable error.
1176      * The application must assume that the transformation cannot continue
1177      * after the Transformer has invoked this method, and should continue
1178      * (if at all) only to collect addition error messages. In fact,
1179      * Transformers are free to stop reporting events once this method has
1180      * been invoked.
1181      *
1182      * @param e warning information encapsulated in a transformer
1183      * exception.
1184      * @throws TransformerException if the application chooses to discontinue
1185      * the transformation (always does in our case).
1186      */
1187     @Override
1188     public void fatalError(TransformerException e)
1189         throws TransformerException
1190     {
1191         Throwable wrapped = e.getException();
1192         if (wrapped != null) {
1193             System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG,
1194                                             e.getMessageAndLocation(),
1195                                             wrapped.getMessage()));
1196         } else {
1197             System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG,
1198                                             e.getMessageAndLocation()));
1199         }
1200         throw e;
1201     }
1202 
1203     /**
1204      * Receive notification of a warning.
1205      * Transformers can use this method to report conditions that are not
1206      * errors or fatal errors. The default behaviour is to take no action.
1207      * After invoking this method, the Transformer must continue with the
1208      * transformation. It should still be possible for the application to
1209      * process the document through to the end.
1210      *
1211      * @param e The warning information encapsulated in a transformer
1212      * exception.
1213      * @throws TransformerException if the application chooses to discontinue
1214      * the transformation (never does in our case).
1215      */
1216     @Override
1217     public void warning(TransformerException e)
1218         throws TransformerException
1219     {
1220         Throwable wrapped = e.getException();
1221         if (wrapped != null) {
1222             System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG,
1223                                             e.getMessageAndLocation(),
1224                                             wrapped.getMessage()));
1225         } else {
1226             System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG,
1227                                             e.getMessageAndLocation()));
1228         }
1229     }
1230 
1231     /**
1232      * This method implements XSLTC's SourceLoader interface. It is used to
1233      * glue a TrAX URIResolver to the XSLTC compiler's Input and Import classes.
1234      *
1235      * @param href The URI of the document to load
1236      * @param context The URI of the currently loaded document
1237      * @param xsltc The compiler that resuests the document
1238      * @return An InputSource with the loaded document
1239      */
1240     @Override
1241     public InputSource loadSource(String href, String context, XSLTC xsltc) {
1242         try {
1243             if (_uriResolver != null) {
1244                 final Source source = _uriResolver.resolve(href, context);
1245                 if (source != null) {
1246                     return Util.getInputSource(xsltc, source);
1247                 }
1248             }
1249         }
1250         catch (TransformerException e) {
1251             // should catch it when the resolver explicitly throws the exception
1252             final ErrorMsg msg = new ErrorMsg(ErrorMsg.INVALID_URI_ERR, href + "\n" + e.getMessage(), this);
1253             xsltc.getParser().reportError(Constants.FATAL, msg);
1254         }
1255 
1256         return null;
1257     }
1258 
1259     /**
1260      * Reset the per-session attributes to their default values
1261      */
1262     private void resetTransientAttributes() {
1263         _transletName = DEFAULT_TRANSLET_NAME;
1264         _destinationDirectory = null;
1265         _packageName = null;
1266         _jarFileName = null;
1267     }
1268 
1269     /**
1270      * Load the translet classes from local .class files and return
1271      * the bytecode array.
1272      *
1273      * @param source The xsl source
1274      * @param fullClassName The full name of the translet
1275      * @return The bytecode array
1276      */
1277     private byte[][] getBytecodesFromClasses(Source source, String fullClassName)
1278     {
1279         if (fullClassName == null)
1280             return null;
1281 
1282         String xslFileName = getStylesheetFileName(source);
1283         File xslFile = null;
1284         if (xslFileName != null)
1285             xslFile = new File(xslFileName);
1286 
1287         // Find the base name of the translet
1288         final String transletName;
1289         int lastDotIndex = fullClassName.lastIndexOf('.');
1290         if (lastDotIndex > 0)
1291             transletName = fullClassName.substring(lastDotIndex+1);
1292         else
1293             transletName = fullClassName;
1294 
1295         // Construct the path name for the translet class file
1296         String transletPath = fullClassName.replace('.', '/');
1297         if (_destinationDirectory != null) {
1298             transletPath = _destinationDirectory + "/" + transletPath + ".class";
1299         }
1300         else {
1301             if (xslFile != null && xslFile.getParent() != null)
1302                 transletPath = xslFile.getParent() + "/" + transletPath + ".class";
1303             else
1304                 transletPath = transletPath + ".class";
1305         }
1306 
1307         // Return null if the translet class file does not exist.
1308         File transletFile = new File(transletPath);
1309         if (!transletFile.exists())
1310             return null;
1311 
1312         // Compare the timestamps of the translet and the xsl file.
1313         // If the translet is older than the xsl file, return null
1314         // so that the xsl file is used for the transformation and
1315         // the translet is regenerated.
1316         if (xslFile != null && xslFile.exists()) {
1317             long xslTimestamp = xslFile.lastModified();
1318             long transletTimestamp = transletFile.lastModified();
1319             if (transletTimestamp < xslTimestamp)
1320                 return null;
1321         }
1322 
1323         // Load the translet into a bytecode array.
1324         Vector bytecodes = new Vector();
1325         int fileLength = (int)transletFile.length();
1326         if (fileLength > 0) {
1327             FileInputStream input;
1328             try {
1329                 input = new FileInputStream(transletFile);
1330             }
1331             catch (FileNotFoundException e) {
1332                 return null;
1333             }
1334 
1335             byte[] bytes = new byte[fileLength];
1336             try {
1337                 readFromInputStream(bytes, input, fileLength);
1338                 input.close();
1339             }
1340             catch (IOException e) {
1341                 return null;
1342             }
1343 
1344             bytecodes.addElement(bytes);
1345         }
1346         else
1347             return null;
1348 
1349         // Find the parent directory of the translet.
1350         String transletParentDir = transletFile.getParent();
1351         if (transletParentDir == null)
1352             transletParentDir = SecuritySupport.getSystemProperty("user.dir");
1353 
1354         File transletParentFile = new File(transletParentDir);
1355 
1356         // Find all the auxiliary files which have a name pattern of "transletClass$nnn.class".
1357         final String transletAuxPrefix = transletName + "$";
1358         File[] auxfiles = transletParentFile.listFiles(new FilenameFilter() {
1359                 @Override
1360                 public boolean accept(File dir, String name)
1361                 {
1362                     return (name.endsWith(".class") && name.startsWith(transletAuxPrefix));
1363                 }
1364               });
1365 
1366         // Load the auxiliary class files and add them to the bytecode array.
1367         for (int i = 0; i < auxfiles.length; i++)
1368         {
1369             File auxfile = auxfiles[i];
1370             int auxlength = (int)auxfile.length();
1371             if (auxlength > 0) {
1372                 FileInputStream auxinput = null;
1373                 try {
1374                     auxinput = new FileInputStream(auxfile);
1375                 }
1376                 catch (FileNotFoundException e) {
1377                     continue;
1378                 }
1379 
1380                 byte[] bytes = new byte[auxlength];
1381 
1382                 try {
1383                     readFromInputStream(bytes, auxinput, auxlength);
1384                     auxinput.close();
1385                 }
1386                 catch (IOException e) {
1387                     continue;
1388                 }
1389 
1390                 bytecodes.addElement(bytes);
1391             }
1392         }
1393 
1394         // Convert the Vector of byte[] to byte[][].
1395         final int count = bytecodes.size();
1396         if ( count > 0) {
1397             final byte[][] result = new byte[count][1];
1398             for (int i = 0; i < count; i++) {
1399                 result[i] = (byte[])bytecodes.elementAt(i);
1400             }
1401 
1402             return result;
1403         }
1404         else
1405             return null;
1406     }
1407 
1408     /**
1409      * Load the translet classes from the jar file and return the bytecode.
1410      *
1411      * @param source The xsl source
1412      * @param fullClassName The full name of the translet
1413      * @return The bytecode array
1414      */
1415     private byte[][] getBytecodesFromJar(Source source, String fullClassName)
1416     {
1417         String xslFileName = getStylesheetFileName(source);
1418         File xslFile = null;
1419         if (xslFileName != null)
1420             xslFile = new File(xslFileName);
1421 
1422         // Construct the path for the jar file
1423         String jarPath;
1424         if (_destinationDirectory != null)
1425             jarPath = _destinationDirectory + "/" + _jarFileName;
1426         else {
1427             if (xslFile != null && xslFile.getParent() != null)
1428                 jarPath = xslFile.getParent() + "/" + _jarFileName;
1429             else
1430                 jarPath = _jarFileName;
1431         }
1432 
1433         // Return null if the jar file does not exist.
1434         File file = new File(jarPath);
1435         if (!file.exists())
1436             return null;
1437 
1438         // Compare the timestamps of the jar file and the xsl file. Return null
1439         // if the xsl file is newer than the jar file.
1440         if (xslFile != null && xslFile.exists()) {
1441             long xslTimestamp = xslFile.lastModified();
1442             long transletTimestamp = file.lastModified();
1443             if (transletTimestamp < xslTimestamp)
1444                 return null;
1445         }
1446 
1447         // Create a ZipFile object for the jar file
1448         ZipFile jarFile;
1449         try {
1450             jarFile = new ZipFile(file);
1451         }
1452         catch (IOException e) {
1453             return null;
1454         }
1455 
1456         String transletPath = fullClassName.replace('.', '/');
1457         String transletAuxPrefix = transletPath + "$";
1458         String transletFullName = transletPath + ".class";
1459 
1460         Vector bytecodes = new Vector();
1461 
1462         // Iterate through all entries in the jar file to find the
1463         // translet and auxiliary classes.
1464         Enumeration entries = jarFile.entries();
1465         while (entries.hasMoreElements())
1466         {
1467             ZipEntry entry = (ZipEntry)entries.nextElement();
1468             String entryName = entry.getName();
1469             if (entry.getSize() > 0 &&
1470                   (entryName.equals(transletFullName) ||
1471                   (entryName.endsWith(".class") &&
1472                       entryName.startsWith(transletAuxPrefix))))
1473             {
1474                 try {
1475                     InputStream input = jarFile.getInputStream(entry);
1476                     int size = (int)entry.getSize();
1477                     byte[] bytes = new byte[size];
1478                     readFromInputStream(bytes, input, size);
1479                     input.close();
1480                     bytecodes.addElement(bytes);
1481                 }
1482                 catch (IOException e) {
1483                     return null;
1484                 }
1485             }
1486         }
1487 
1488         // Convert the Vector of byte[] to byte[][].
1489         final int count = bytecodes.size();
1490         if (count > 0) {
1491             final byte[][] result = new byte[count][1];
1492             for (int i = 0; i < count; i++) {
1493                 result[i] = (byte[])bytecodes.elementAt(i);
1494             }
1495 
1496             return result;
1497         }
1498         else
1499             return null;
1500     }
1501 
1502     /**
1503      * Read a given number of bytes from the InputStream into a byte array.
1504      *
1505      * @param bytes The byte array to store the input content.
1506      * @param input The input stream.
1507      * @param size The number of bytes to read.
1508      */
1509     private void readFromInputStream(byte[] bytes, InputStream input, int size)
1510         throws IOException
1511     {
1512       int n = 0;
1513       int offset = 0;
1514       int length = size;
1515       while (length > 0 && (n = input.read(bytes, offset, length)) > 0) {
1516           offset = offset + n;
1517           length = length - n;
1518       }
1519     }
1520 
1521     /**
1522      * Return the base class name of the translet.
1523      * The translet name is resolved using the following rules:
1524      * 1. if the _transletName attribute is set and its value is not "GregorSamsa",
1525      *    then _transletName is returned.
1526      * 2. otherwise get the translet name from the base name of the system ID
1527      * 3. return "GregorSamsa" if the result from step 2 is null.
1528      *
1529      * @param source The input Source
1530      * @return The name of the translet class
1531      */
1532     private String getTransletBaseName(Source source)
1533     {
1534         String transletBaseName = null;
1535         if (!_transletName.equals(DEFAULT_TRANSLET_NAME))
1536             return _transletName;
1537         else {
1538             String systemId = source.getSystemId();
1539             if (systemId != null) {
1540                 String baseName = Util.baseName(systemId);
1541                 if (baseName != null) {
1542                     baseName = Util.noExtName(baseName);
1543                     transletBaseName = Util.toJavaName(baseName);
1544                 }
1545             }
1546         }
1547 
1548         return (transletBaseName != null) ? transletBaseName : DEFAULT_TRANSLET_NAME;
1549     }
1550 
1551     /**
1552      *  Return the local file name from the systemId of the Source object
1553      *
1554      * @param source The Source
1555      * @return The file name in the local filesystem, or null if the
1556      * systemId does not represent a local file.
1557      */
1558     private String getStylesheetFileName(Source source)
1559     {
1560         String systemId = source.getSystemId();
1561         if (systemId != null) {
1562             File file = new File(systemId);
1563             if (file.exists())
1564                 return systemId;
1565             else {
1566                 URL url;
1567                 try {
1568                     url = new URL(systemId);
1569                 }
1570                 catch (MalformedURLException e) {
1571                     return null;
1572                 }
1573 
1574                 if ("file".equals(url.getProtocol()))
1575                     return url.getFile();
1576                 else
1577                     return null;
1578             }
1579         }
1580         else
1581             return null;
1582     }
1583 
1584     /**
1585      * Returns a new instance of the XSLTC DTM Manager service.
1586      */
1587     protected final XSLTCDTMManager createNewDTMManagerInstance() {
1588         return XSLTCDTMManager.createNewDTMManagerInstance();
1589     }
1590 }