1 /* 2 * Copyright (c) 2007, 2018, 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: July 2018 88 */ 89 public class TransformerFactoryImpl 90 extends SAXTransformerFactory implements SourceLoader, ErrorListener 91 { 92 // Public constants for attributes supported by the XSLTC TransformerFactory. 93 public final static String TRANSLET_NAME = "translet-name"; 94 public final static String DESTINATION_DIRECTORY = "destination-directory"; 95 public final static String PACKAGE_NAME = "package-name"; 96 public final static String JAR_NAME = "jar-name"; 97 public final static String GENERATE_TRANSLET = "generate-translet"; 98 public final static String AUTO_TRANSLET = "auto-translet"; 99 public final static String USE_CLASSPATH = "use-classpath"; 100 public final static String DEBUG = "debug"; 101 public final static String ENABLE_INLINING = "enable-inlining"; 102 public final static String INDENT_NUMBER = "indent-number"; 103 104 /** 105 * This error listener is used only for this factory and is not passed to 106 * the Templates or Transformer objects that we create. 107 */ 108 private ErrorListener _errorListener = this; 109 110 /** 111 * This URIResolver is passed to all created Templates and Transformers 112 */ 113 private URIResolver _uriResolver = null; 114 115 /** 116 * As Gregor Samsa awoke one morning from uneasy dreams he found himself 117 * transformed in his bed into a gigantic insect. He was lying on his hard, 118 * as it were armour plated, back, and if he lifted his head a little he 119 * could see his big, brown belly divided into stiff, arched segments, on 120 * top of which the bed quilt could hardly keep in position and was about 121 * to slide off completely. His numerous legs, which were pitifully thin 122 * compared to the rest of his bulk, waved helplessly before his eyes. 123 * "What has happened to me?", he thought. It was no dream.... 124 */ 125 protected final static String DEFAULT_TRANSLET_NAME = "GregorSamsa"; 126 127 /** 128 * The class name of the translet 129 */ 130 private String _transletName = DEFAULT_TRANSLET_NAME; 131 132 /** 133 * The destination directory for the translet 134 */ 135 private String _destinationDirectory = null; 136 137 /** 138 * The package name prefix for all generated translet classes 139 */ 140 private static final String DEFAULT_TRANSLATE_PACKAGE = "die.verwandlung"; 141 private String _packageName = DEFAULT_TRANSLATE_PACKAGE; 142 143 /** 144 * The jar file name which the translet classes are packaged into 145 */ 146 private String _jarFileName = null; 147 148 /** 149 * This Map is used to store parameters for locating 150 * <?xml-stylesheet ...?> processing instructions in XML docs. 151 */ 152 private Map<Source, PIParamWrapper> _piParams = null; 153 154 /** 155 * The above Map stores objects of this class. 156 */ 157 private static class PIParamWrapper { 158 public String _media = null; 159 public String _title = null; 160 public String _charset = null; 161 162 public PIParamWrapper(String media, String title, String charset) { 163 _media = media; 164 _title = title; 165 _charset = charset; 166 } 167 } 168 169 /** 170 * Set to <code>true</code> when debugging is enabled. 171 */ 172 private boolean _debug = false; 173 174 /** 175 * Set to <code>true</code> when templates are inlined. 176 */ 177 private boolean _enableInlining = false; 178 179 /** 180 * Set to <code>true</code> when we want to generate 181 * translet classes from the stylesheet. 182 */ 183 private boolean _generateTranslet = false; 184 185 /** 186 * If this is set to <code>true</code>, we attempt to use translet classes 187 * for transformation if possible without compiling the stylesheet. The 188 * translet class is only used if its timestamp is newer than the timestamp 189 * of the stylesheet. 190 */ 191 private boolean _autoTranslet = false; 192 193 /** 194 * If this is set to <code>true</code>, we attempt to load the translet 195 * from the CLASSPATH. 196 */ 197 private boolean _useClasspath = false; 198 199 /** 200 * Number of indent spaces when indentation is turned on. 201 */ 202 private int _indentNumber = -1; 203 204 /** 205 * <p>State of secure processing feature.</p> 206 */ 207 private boolean _isNotSecureProcessing = true; 208 /** 209 * <p>State of secure mode.</p> 210 */ 211 private boolean _isSecureMode = false; 212 213 /** 214 * Indicates whether 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 */ 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 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 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 310 public ErrorListener getErrorListener() { 311 return _errorListener; 312 } 313 314 /** 315 * Returns the package name. 316 */ 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 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 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 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 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 */ 663 public boolean overrideDefaultParser() { 664 return _overrideDefaultParser; 665 } 666 667 /** 668 * @return the feature manager 669 */ 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 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 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 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 throw 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 1693 protected final XSLTCDTMManager createNewDTMManagerInstance() { 1694 return XSLTCDTMManager.createNewDTMManagerInstance(); 1695 } 1696 }