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