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