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