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