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