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