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