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