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