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