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