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