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