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