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