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