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