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