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