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