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