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