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