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