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