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: AbstractTranslet.java,v 1.6 2006/06/19 19:49:03 spericas Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.runtime; 25 26 import com.sun.org.apache.xalan.internal.XalanConstants; 27 import com.sun.org.apache.xalan.internal.utils.FactoryImpl; 28 import java.io.File; 29 import java.io.FileOutputStream; 30 import java.io.BufferedOutputStream; 31 import java.text.DecimalFormat; 32 import java.text.DecimalFormatSymbols; 33 import java.util.ArrayList; 34 import java.util.Enumeration; 35 import java.util.Vector; 36 import javax.xml.transform.Templates; 37 import javax.xml.parsers.DocumentBuilderFactory; 38 import org.w3c.dom.Document; 39 import org.w3c.dom.DOMImplementation; 40 import javax.xml.parsers.ParserConfigurationException; 41 42 import com.sun.org.apache.xml.internal.dtm.DTM; 43 44 import com.sun.org.apache.xalan.internal.xsltc.DOM; 45 import com.sun.org.apache.xalan.internal.xsltc.DOMCache; 46 import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM; 47 import com.sun.org.apache.xalan.internal.xsltc.Translet; 48 import com.sun.org.apache.xalan.internal.xsltc.TransletException; 49 import com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter; 50 import com.sun.org.apache.xalan.internal.xsltc.dom.KeyIndex; 51 import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory; 52 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 53 import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 54 55 /** 56 * @author Jacek Ambroziak 57 * @author Santiago Pericas-Geertsen 58 * @author Morten Jorgensen 59 * @author G. Todd Miller 60 * @author John Howard, JohnH@schemasoft.com 61 */ 62 public abstract class AbstractTranslet implements Translet { 63 64 // These attributes are extracted from the xsl:output element. They also 65 // appear as fields (with the same type, only public) in Output.java 66 public String _version = "1.0"; 67 public String _method = null; 68 public String _encoding = "UTF-8"; 69 public boolean _omitHeader = false; 70 public String _standalone = null; 71 //see OutputPropertiesFactory.ORACLE_IS_STANDALONE 72 public boolean _isStandalone = false; 73 public String _doctypePublic = null; 74 public String _doctypeSystem = null; 75 public boolean _indent = false; 76 public String _mediaType = null; 77 public Vector _cdata = null; 78 public int _indentamount = -1; 79 80 public static final int FIRST_TRANSLET_VERSION = 100; 81 public static final int VER_SPLIT_NAMES_ARRAY = 101; 82 public static final int CURRENT_TRANSLET_VERSION = VER_SPLIT_NAMES_ARRAY; 83 84 // Initialize Translet version field to base value. A class that extends 85 // AbstractTranslet may override this value to a more recent translet 86 // version; if it doesn't override the value (because it was compiled 87 // before the notion of a translet version was introduced, it will get 88 // this default value). 89 protected int transletVersion = FIRST_TRANSLET_VERSION; 90 91 // DOM/translet handshaking - the arrays are set by the compiled translet 92 protected String[] namesArray; 93 protected String[] urisArray; 94 protected int[] typesArray; 95 protected String[] namespaceArray; 96 97 // The Templates object that is used to create this Translet instance 98 protected Templates _templates = null; 99 100 // Boolean flag to indicate whether this translet has id functions. 101 protected boolean _hasIdCall = false; 102 103 // TODO - these should only be instanciated when needed 104 protected StringValueHandler stringValueHandler = new StringValueHandler(); 105 106 // Use one empty string instead of constantly instanciating String(""); 107 private final static String EMPTYSTRING = ""; 108 109 // This is the name of the index used for ID attributes 110 private final static String ID_INDEX_NAME = "##id"; 111 112 private boolean _useServicesMechanism; 113 114 /** 115 * protocols allowed for external references set by the stylesheet processing instruction, Document() function, Import and Include element. 116 */ 117 private String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT; 118 119 /************************************************************************ 120 * Debugging 121 ************************************************************************/ 122 public void printInternalState() { 123 System.out.println("-------------------------------------"); 124 System.out.println("AbstractTranslet this = " + this); 125 System.out.println("pbase = " + pbase); 126 System.out.println("vframe = " + pframe); 127 System.out.println("paramsStack.size() = " + paramsStack.size()); 128 System.out.println("namesArray.size = " + namesArray.length); 129 System.out.println("namespaceArray.size = " + namespaceArray.length); 130 System.out.println(""); 131 System.out.println("Total memory = " + Runtime.getRuntime().totalMemory()); 132 } 133 134 /** 135 * Wrap the initial input DOM in a dom adapter. This adapter is wrapped in 136 * a DOM multiplexer if the document() function is used (handled by compiled 137 * code in the translet - see compiler/Stylesheet.compileTransform()). 138 */ 139 public final DOMAdapter makeDOMAdapter(DOM dom) 140 throws TransletException { 141 setRootForKeys(dom.getDocument()); 142 return new DOMAdapter(dom, namesArray, urisArray, typesArray, namespaceArray); 143 } 144 145 /************************************************************************ 146 * Parameter handling 147 ************************************************************************/ 148 149 // Parameter's stack: <tt>pbase</tt> and <tt>pframe</tt> are used 150 // to denote the current parameter frame. 151 protected int pbase = 0, pframe = 0; 152 protected ArrayList paramsStack = new ArrayList(); 153 154 /** 155 * Push a new parameter frame. 156 */ 157 public final void pushParamFrame() { 158 paramsStack.add(pframe, new Integer(pbase)); 159 pbase = ++pframe; 160 } 161 162 /** 163 * Pop the topmost parameter frame. 164 */ 165 public final void popParamFrame() { 166 if (pbase > 0) { 167 final int oldpbase = ((Integer)paramsStack.get(--pbase)).intValue(); 168 for (int i = pframe - 1; i >= pbase; i--) { 169 paramsStack.remove(i); 170 } 171 pframe = pbase; pbase = oldpbase; 172 } 173 } 174 175 /** 176 * Add a new global parameter if not already in the current frame. 177 * To setParameters of the form {http://foo.bar}xyz 178 * This needs to get mapped to an instance variable in the class 179 * The mapping created so that 180 * the global variables in the generated class become 181 * http$colon$$flash$$flash$foo$dot$bar$colon$xyz 182 */ 183 public final Object addParameter(String name, Object value) { 184 name = BasisLibrary.mapQNameToJavaName (name); 185 return addParameter(name, value, false); 186 } 187 188 /** 189 * Add a new global or local parameter if not already in the current frame. 190 * The 'isDefault' parameter is set to true if the value passed is the 191 * default value from the <xsl:parameter> element's select attribute or 192 * element body. 193 */ 194 public final Object addParameter(String name, Object value, 195 boolean isDefault) 196 { 197 // Local parameters need to be re-evaluated for each iteration 198 for (int i = pframe - 1; i >= pbase; i--) { 199 final Parameter param = (Parameter) paramsStack.get(i); 200 201 if (param._name.equals(name)) { 202 // Only overwrite if current value is the default value and 203 // the new value is _NOT_ the default value. 204 if (param._isDefault || !isDefault) { 205 param._value = value; 206 param._isDefault = isDefault; 207 return value; 208 } 209 return param._value; 210 } 211 } 212 213 // Add new parameter to parameter stack 214 paramsStack.add(pframe++, new Parameter(name, value, isDefault)); 215 return value; 216 } 217 218 /** 219 * Clears the parameter stack. 220 */ 221 public void clearParameters() { 222 pbase = pframe = 0; 223 paramsStack.clear(); 224 } 225 226 /** 227 * Get the value of a parameter from the current frame or 228 * <tt>null</tt> if undefined. 229 */ 230 public final Object getParameter(String name) { 231 232 name = BasisLibrary.mapQNameToJavaName (name); 233 234 for (int i = pframe - 1; i >= pbase; i--) { 235 final Parameter param = (Parameter)paramsStack.get(i); 236 if (param._name.equals(name)) return param._value; 237 } 238 return null; 239 } 240 241 /************************************************************************ 242 * Message handling - implementation of <xsl:message> 243 ************************************************************************/ 244 245 // Holds the translet's message handler - used for <xsl:message>. 246 // The deault message handler dumps a string stdout, but anything can be 247 // used, such as a dialog box for applets, etc. 248 private MessageHandler _msgHandler = null; 249 250 /** 251 * Set the translet's message handler - must implement MessageHandler 252 */ 253 public final void setMessageHandler(MessageHandler handler) { 254 _msgHandler = handler; 255 } 256 257 /** 258 * Pass a message to the message handler - used by Message class. 259 */ 260 public final void displayMessage(String msg) { 261 if (_msgHandler == null) { 262 System.err.println(msg); 263 } 264 else { 265 _msgHandler.displayMessage(msg); 266 } 267 } 268 269 /************************************************************************ 270 * Decimal number format symbol handling 271 ************************************************************************/ 272 273 // Contains decimal number formatting symbols used by FormatNumberCall 274 public Hashtable _formatSymbols = null; 275 276 /** 277 * Adds a DecimalFormat object to the _formatSymbols hashtable. 278 * The entry is created with the input DecimalFormatSymbols. 279 */ 280 public void addDecimalFormat(String name, DecimalFormatSymbols symbols) { 281 // Instanciate hashtable for formatting symbols if needed 282 if (_formatSymbols == null) _formatSymbols = new Hashtable(); 283 284 // The name cannot be null - use empty string instead 285 if (name == null) name = EMPTYSTRING; 286 287 // Construct a DecimalFormat object containing the symbols we got 288 final DecimalFormat df = new DecimalFormat(); 289 if (symbols != null) { 290 df.setDecimalFormatSymbols(symbols); 291 } 292 _formatSymbols.put(name, df); 293 } 294 295 /** 296 * Retrieves a named DecimalFormat object from _formatSymbols hashtable. 297 */ 298 public final DecimalFormat getDecimalFormat(String name) { 299 300 if (_formatSymbols != null) { 301 // The name cannot be null - use empty string instead 302 if (name == null) name = EMPTYSTRING; 303 304 DecimalFormat df = (DecimalFormat)_formatSymbols.get(name); 305 if (df == null) df = (DecimalFormat)_formatSymbols.get(EMPTYSTRING); 306 return df; 307 } 308 return(null); 309 } 310 311 /** 312 * Give the translet an opportunity to perform a prepass on the document 313 * to extract any information that it can store in an optimized form. 314 * 315 * Currently, it only extracts information about attributes of type ID. 316 */ 317 public final void prepassDocument(DOM document) { 318 setIndexSize(document.getSize()); 319 buildIDIndex(document); 320 } 321 322 /** 323 * Leverages the Key Class to implement the XSLT id() function. 324 * buildIdIndex creates the index (##id) that Key Class uses. 325 * The index contains the element node index (int) and Id value (String). 326 */ 327 private final void buildIDIndex(DOM document) { 328 setRootForKeys(document.getDocument()); 329 330 if (document instanceof DOMEnhancedForDTM) { 331 DOMEnhancedForDTM enhancedDOM = (DOMEnhancedForDTM)document; 332 333 // If the input source is DOMSource, the KeyIndex table is not 334 // built at this time. It will be built later by the lookupId() 335 // and containsId() methods of the KeyIndex class. 336 if (enhancedDOM.hasDOMSource()) { 337 buildKeyIndex(ID_INDEX_NAME, document); 338 return; 339 } 340 else { 341 final Hashtable elementsByID = enhancedDOM.getElementsWithIDs(); 342 343 if (elementsByID == null) { 344 return; 345 } 346 347 // Given a Hashtable of DTM nodes indexed by ID attribute values, 348 // loop through the table copying information to a KeyIndex 349 // for the mapping from ID attribute value to DTM node 350 final Enumeration idValues = elementsByID.keys(); 351 boolean hasIDValues = false; 352 353 while (idValues.hasMoreElements()) { 354 final Object idValue = idValues.nextElement(); 355 final int element = 356 document.getNodeHandle( 357 ((Integer)elementsByID.get(idValue)) 358 .intValue()); 359 360 buildKeyIndex(ID_INDEX_NAME, element, idValue); 361 hasIDValues = true; 362 } 363 364 if (hasIDValues) { 365 setKeyIndexDom(ID_INDEX_NAME, document); 366 } 367 } 368 } 369 } 370 371 /** 372 * After constructing the translet object, this method must be called to 373 * perform any version-specific post-initialization that's required. 374 */ 375 public final void postInitialization() { 376 // If the version of the translet had just one namesArray, split 377 // it into multiple fields. 378 if (transletVersion < VER_SPLIT_NAMES_ARRAY) { 379 int arraySize = namesArray.length; 380 String[] newURIsArray = new String[arraySize]; 381 String[] newNamesArray = new String[arraySize]; 382 int[] newTypesArray = new int[arraySize]; 383 384 for (int i = 0; i < arraySize; i++) { 385 String name = namesArray[i]; 386 int colonIndex = name.lastIndexOf(':'); 387 int lNameStartIdx = colonIndex+1; 388 389 if (colonIndex > -1) { 390 newURIsArray[i] = name.substring(0, colonIndex); 391 } 392 393 // Distinguish attribute and element names. Attribute has 394 // @ before local part of name. 395 if (name.charAt(lNameStartIdx) == '@') { 396 lNameStartIdx++; 397 newTypesArray[i] = DTM.ATTRIBUTE_NODE; 398 } else if (name.charAt(lNameStartIdx) == '?') { 399 lNameStartIdx++; 400 newTypesArray[i] = DTM.NAMESPACE_NODE; 401 } else { 402 newTypesArray[i] = DTM.ELEMENT_NODE; 403 } 404 newNamesArray[i] = 405 (lNameStartIdx == 0) ? name 406 : name.substring(lNameStartIdx); 407 } 408 409 namesArray = newNamesArray; 410 urisArray = newURIsArray; 411 typesArray = newTypesArray; 412 } 413 414 // Was translet compiled using a more recent version of the XSLTC 415 // compiler than is known by the AbstractTranslet class? If, so 416 // and we've made it this far (which is doubtful), we should give up. 417 if (transletVersion > CURRENT_TRANSLET_VERSION) { 418 BasisLibrary.runTimeError(BasisLibrary.UNKNOWN_TRANSLET_VERSION_ERR, 419 this.getClass().getName()); 420 } 421 } 422 423 /************************************************************************ 424 * Index(es) for <xsl:key> / key() / id() 425 ************************************************************************/ 426 427 // Container for all indexes for xsl:key elements 428 private Hashtable _keyIndexes = null; 429 private KeyIndex _emptyKeyIndex = null; 430 private int _indexSize = 0; 431 private int _currentRootForKeys = 0; 432 433 /** 434 * This method is used to pass the largest DOM size to the translet. 435 * Needed to make sure that the translet can index the whole DOM. 436 */ 437 public void setIndexSize(int size) { 438 if (size > _indexSize) _indexSize = size; 439 } 440 441 /** 442 * Creates a KeyIndex object of the desired size - don't want to resize!!! 443 */ 444 public KeyIndex createKeyIndex() { 445 return(new KeyIndex(_indexSize)); 446 } 447 448 /** 449 * Adds a value to a key/id index 450 * @param name is the name of the index (the key or ##id) 451 * @param node is the node handle of the node to insert 452 * @param value is the value that will look up the node in the given index 453 */ 454 public void buildKeyIndex(String name, int node, Object value) { 455 if (_keyIndexes == null) _keyIndexes = new Hashtable(); 456 457 KeyIndex index = (KeyIndex)_keyIndexes.get(name); 458 if (index == null) { 459 _keyIndexes.put(name, index = new KeyIndex(_indexSize)); 460 } 461 index.add(value, node, _currentRootForKeys); 462 } 463 464 /** 465 * Create an empty KeyIndex in the DOM case 466 * @param name is the name of the index (the key or ##id) 467 * @param dom is the DOM 468 */ 469 public void buildKeyIndex(String name, DOM dom) { 470 if (_keyIndexes == null) _keyIndexes = new Hashtable(); 471 472 KeyIndex index = (KeyIndex)_keyIndexes.get(name); 473 if (index == null) { 474 _keyIndexes.put(name, index = new KeyIndex(_indexSize)); 475 } 476 index.setDom(dom, dom.getDocument()); 477 } 478 479 /** 480 * Returns the index for a given key (or id). 481 * The index implements our internal iterator interface 482 */ 483 public KeyIndex getKeyIndex(String name) { 484 // Return an empty key index iterator if none are defined 485 if (_keyIndexes == null) { 486 return (_emptyKeyIndex != null) 487 ? _emptyKeyIndex 488 : (_emptyKeyIndex = new KeyIndex(1)); 489 } 490 491 // Look up the requested key index 492 final KeyIndex index = (KeyIndex)_keyIndexes.get(name); 493 494 // Return an empty key index iterator if the requested index not found 495 if (index == null) { 496 return (_emptyKeyIndex != null) 497 ? _emptyKeyIndex 498 : (_emptyKeyIndex = new KeyIndex(1)); 499 } 500 501 return(index); 502 } 503 504 private void setRootForKeys(int root) { 505 _currentRootForKeys = root; 506 } 507 508 /** 509 * This method builds key indexes - it is overridden in the compiled 510 * translet in cases where the <xsl:key> element is used 511 */ 512 public void buildKeys(DOM document, DTMAxisIterator iterator, 513 SerializationHandler handler, 514 int root) throws TransletException { 515 516 } 517 518 /** 519 * This method builds key indexes - it is overridden in the compiled 520 * translet in cases where the <xsl:key> element is used 521 */ 522 public void setKeyIndexDom(String name, DOM document) { 523 getKeyIndex(name).setDom(document, document.getDocument()); 524 } 525 526 /************************************************************************ 527 * DOM cache handling 528 ************************************************************************/ 529 530 // Hold the DOM cache (if any) used with this translet 531 private DOMCache _domCache = null; 532 533 /** 534 * Sets the DOM cache used for additional documents loaded using the 535 * document() function. 536 */ 537 public void setDOMCache(DOMCache cache) { 538 _domCache = cache; 539 } 540 541 /** 542 * Returns the DOM cache used for this translet. Used by the LoadDocument 543 * class (if present) when the document() function is used. 544 */ 545 public DOMCache getDOMCache() { 546 return(_domCache); 547 } 548 549 /************************************************************************ 550 * Multiple output document extension. 551 * See compiler/TransletOutput for actual implementation. 552 ************************************************************************/ 553 554 public SerializationHandler openOutputHandler(String filename, boolean append) 555 throws TransletException 556 { 557 try { 558 final TransletOutputHandlerFactory factory 559 = TransletOutputHandlerFactory.newInstance(); 560 561 String dirStr = new File(filename).getParent(); 562 if ((null != dirStr) && (dirStr.length() > 0)) { 563 File dir = new File(dirStr); 564 dir.mkdirs(); 565 } 566 567 factory.setEncoding(_encoding); 568 factory.setOutputMethod(_method); 569 factory.setOutputStream(new BufferedOutputStream(new FileOutputStream(filename, append))); 570 factory.setOutputType(TransletOutputHandlerFactory.STREAM); 571 572 final SerializationHandler handler 573 = factory.getSerializationHandler(); 574 575 transferOutputSettings(handler); 576 handler.startDocument(); 577 return handler; 578 } 579 catch (Exception e) { 580 throw new TransletException(e); 581 } 582 } 583 584 public SerializationHandler openOutputHandler(String filename) 585 throws TransletException 586 { 587 return openOutputHandler(filename, false); 588 } 589 590 public void closeOutputHandler(SerializationHandler handler) { 591 try { 592 handler.endDocument(); 593 handler.close(); 594 } 595 catch (Exception e) { 596 // what can you do? 597 } 598 } 599 600 /************************************************************************ 601 * Native API transformation methods - _NOT_ JAXP/TrAX 602 ************************************************************************/ 603 604 /** 605 * Main transform() method - this is overridden by the compiled translet 606 */ 607 public abstract void transform(DOM document, DTMAxisIterator iterator, 608 SerializationHandler handler) 609 throws TransletException; 610 611 /** 612 * Calls transform() with a given output handler 613 */ 614 public final void transform(DOM document, SerializationHandler handler) 615 throws TransletException { 616 try { 617 transform(document, document.getIterator(), handler); 618 } finally { 619 _keyIndexes = null; 620 } 621 } 622 623 /** 624 * Used by some compiled code as a shortcut for passing strings to the 625 * output handler 626 */ 627 public final void characters(final String string, 628 SerializationHandler handler) 629 throws TransletException { 630 if (string != null) { 631 //final int length = string.length(); 632 try { 633 handler.characters(string); 634 } catch (Exception e) { 635 throw new TransletException(e); 636 } 637 } 638 } 639 640 /** 641 * Add's a name of an element whose text contents should be output as CDATA 642 */ 643 public void addCdataElement(String name) { 644 if (_cdata == null) { 645 _cdata = new Vector(); 646 } 647 648 int lastColon = name.lastIndexOf(':'); 649 650 if (lastColon > 0) { 651 String uri = name.substring(0, lastColon); 652 String localName = name.substring(lastColon+1); 653 _cdata.addElement(uri); 654 _cdata.addElement(localName); 655 } else { 656 _cdata.addElement(null); 657 _cdata.addElement(name); 658 } 659 } 660 661 /** 662 * Transfer the output settings to the output post-processor 663 */ 664 protected void transferOutputSettings(SerializationHandler handler) { 665 if (_method != null) { 666 if (_method.equals("xml")) { 667 if (_standalone != null) { 668 handler.setStandalone(_standalone); 669 } 670 if (_omitHeader) { 671 handler.setOmitXMLDeclaration(true); 672 } 673 handler.setCdataSectionElements(_cdata); 674 if (_version != null) { 675 handler.setVersion(_version); 676 } 677 handler.setIndent(_indent); 678 handler.setIndentAmount(_indentamount); 679 if (_doctypeSystem != null) { 680 handler.setDoctype(_doctypeSystem, _doctypePublic); 681 } 682 handler.setIsStandalone(_isStandalone); 683 } 684 else if (_method.equals("html")) { 685 handler.setIndent(_indent); 686 handler.setDoctype(_doctypeSystem, _doctypePublic); 687 if (_mediaType != null) { 688 handler.setMediaType(_mediaType); 689 } 690 } 691 } 692 else { 693 handler.setCdataSectionElements(_cdata); 694 if (_version != null) { 695 handler.setVersion(_version); 696 } 697 if (_standalone != null) { 698 handler.setStandalone(_standalone); 699 } 700 if (_omitHeader) { 701 handler.setOmitXMLDeclaration(true); 702 } 703 handler.setIndent(_indent); 704 handler.setDoctype(_doctypeSystem, _doctypePublic); 705 handler.setIsStandalone(_isStandalone); 706 } 707 } 708 709 private Hashtable _auxClasses = null; 710 711 public void addAuxiliaryClass(Class auxClass) { 712 if (_auxClasses == null) _auxClasses = new Hashtable(); 713 _auxClasses.put(auxClass.getName(), auxClass); 714 } 715 716 public void setAuxiliaryClasses(Hashtable auxClasses) { 717 _auxClasses = auxClasses; 718 } 719 720 public Class getAuxiliaryClass(String className) { 721 if (_auxClasses == null) return null; 722 return((Class)_auxClasses.get(className)); 723 } 724 725 // GTM added (see pg 110) 726 public String[] getNamesArray() { 727 return namesArray; 728 } 729 730 public String[] getUrisArray() { 731 return urisArray; 732 } 733 734 public int[] getTypesArray() { 735 return typesArray; 736 } 737 738 public String[] getNamespaceArray() { 739 return namespaceArray; 740 } 741 742 public boolean hasIdCall() { 743 return _hasIdCall; 744 } 745 746 public Templates getTemplates() { 747 return _templates; 748 } 749 750 public void setTemplates(Templates templates) { 751 _templates = templates; 752 } 753 /** 754 * Return the state of the services mechanism feature. 755 */ 756 public boolean useServicesMechnism() { 757 return _useServicesMechanism; 758 } 759 760 /** 761 * Set the state of the services mechanism feature. 762 */ 763 public void setServicesMechnism(boolean flag) { 764 _useServicesMechanism = flag; 765 } 766 767 /** 768 * Return allowed protocols for accessing external stylesheet. 769 */ 770 public String getAllowedProtocols() { 771 return _accessExternalStylesheet; 772 } 773 774 /** 775 * Set allowed protocols for accessing external stylesheet. 776 */ 777 public void setAllowedProtocols(String protocols) { 778 _accessExternalStylesheet = protocols; 779 } 780 781 /************************************************************************ 782 * DOMImplementation caching for basis library 783 ************************************************************************/ 784 protected DOMImplementation _domImplementation = null; 785 786 public Document newDocument(String uri, String qname) 787 throws ParserConfigurationException 788 { 789 if (_domImplementation == null) { 790 DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(_useServicesMechanism); 791 _domImplementation = dbf.newDocumentBuilder().getDOMImplementation(); 792 } 793 return _domImplementation.createDocument(uri, qname, null); 794 } 795 }