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