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