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: MultiDOM.java,v 1.5 2005/09/28 13:48:36 pvedula Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.dom; 25 26 import com.sun.org.apache.xalan.internal.xsltc.DOM; 27 import com.sun.org.apache.xalan.internal.xsltc.StripFilter; 28 import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 29 import com.sun.org.apache.xalan.internal.xsltc.TransletException; 30 import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary; 31 import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable; 32 import com.sun.org.apache.xml.internal.dtm.DTM; 33 import com.sun.org.apache.xml.internal.dtm.Axis; 34 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 35 import com.sun.org.apache.xml.internal.dtm.DTMManager; 36 import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase; 37 import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; 38 import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector; 39 40 import org.w3c.dom.Node; 41 import org.w3c.dom.NodeList; 42 43 /** 44 * @author Jacek Ambroziak 45 * @author Morten Jorgensen 46 * @author Erwin Bolwidt <ejb@klomp.org> 47 */ 48 public final class MultiDOM implements DOM { 49 50 private static final int NO_TYPE = DOM.FIRST_TYPE - 2; 51 private static final int INITIAL_SIZE = 4; 52 53 private DOM[] _adapters; 54 private DOMAdapter _main; 55 private DTMManager _dtmManager; 56 private int _free; 57 private int _size; 58 59 private Hashtable _documents = new Hashtable(); 60 61 private final class AxisIterator extends DTMAxisIteratorBase { 62 // constitutive data 63 private final int _axis; 64 private final int _type; 65 // implementation mechanism 66 private DTMAxisIterator _source; 67 private int _dtmId = -1; 68 69 public AxisIterator(final int axis, final int type) { 70 _axis = axis; 71 _type = type; 72 } 73 74 public int next() { 75 if (_source == null) { 76 return(END); 77 } 78 return _source.next(); 79 } 80 81 82 public void setRestartable(boolean flag) { 83 if (_source != null) { 84 _source.setRestartable(flag); 85 } 86 } 87 88 public DTMAxisIterator setStartNode(final int node) { 89 if (node == DTM.NULL) { 90 return this; 91 } 92 93 int dom = node >>> DTMManager.IDENT_DTM_NODE_BITS; 94 95 // Get a new source first time and when mask changes 96 if (_source == null || _dtmId != dom) { 97 if (_type == NO_TYPE) { 98 _source = _adapters[dom].getAxisIterator(_axis); 99 } else if (_axis == Axis.CHILD) { 100 _source = _adapters[dom].getTypedChildren(_type); 101 } else { 102 _source = _adapters[dom].getTypedAxisIterator(_axis, _type); 103 } 104 } 105 106 _dtmId = dom; 107 _source.setStartNode(node); 108 return this; 109 } 110 111 public DTMAxisIterator reset() { 112 if (_source != null) { 113 _source.reset(); 114 } 115 return this; 116 } 117 118 public int getLast() { 119 if (_source != null) { 120 return _source.getLast(); 121 } 122 else { 123 return END; 124 } 125 } 126 127 public int getPosition() { 128 if (_source != null) { 129 return _source.getPosition(); 130 } 131 else { 132 return END; 133 } 134 } 135 136 public boolean isReverse() { 137 return Axis.isReverse(_axis); 138 } 139 140 public void setMark() { 141 if (_source != null) { 142 _source.setMark(); 143 } 144 } 145 146 public void gotoMark() { 147 if (_source != null) { 148 _source.gotoMark(); 149 } 150 } 151 152 public DTMAxisIterator cloneIterator() { 153 final AxisIterator clone = new AxisIterator(_axis, _type); 154 if (_source != null) { 155 clone._source = _source.cloneIterator(); 156 } 157 clone._dtmId = _dtmId; 158 return clone; 159 } 160 } // end of AxisIterator 161 162 163 /************************************************************** 164 * This is a specialised iterator for predicates comparing node or 165 * attribute values to variable or parameter values. 166 */ 167 private final class NodeValueIterator extends DTMAxisIteratorBase { 168 169 private DTMAxisIterator _source; 170 private String _value; 171 private boolean _op; 172 private final boolean _isReverse; 173 private int _returnType = RETURN_PARENT; 174 175 public NodeValueIterator(DTMAxisIterator source, int returnType, 176 String value, boolean op) { 177 _source = source; 178 _returnType = returnType; 179 _value = value; 180 _op = op; 181 _isReverse = source.isReverse(); 182 } 183 184 public boolean isReverse() { 185 return _isReverse; 186 } 187 188 public DTMAxisIterator cloneIterator() { 189 try { 190 NodeValueIterator clone = (NodeValueIterator)super.clone(); 191 clone._source = _source.cloneIterator(); 192 clone.setRestartable(false); 193 return clone.reset(); 194 } 195 catch (CloneNotSupportedException e) { 196 BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, 197 e.toString()); 198 return null; 199 } 200 } 201 202 203 public void setRestartable(boolean isRestartable) { 204 _isRestartable = isRestartable; 205 _source.setRestartable(isRestartable); 206 } 207 208 public DTMAxisIterator reset() { 209 _source.reset(); 210 return resetPosition(); 211 } 212 213 public int next() { 214 215 int node; 216 while ((node = _source.next()) != END) { 217 String val = getStringValueX(node); 218 if (_value.equals(val) == _op) { 219 if (_returnType == RETURN_CURRENT) 220 return returnNode(node); 221 else 222 return returnNode(getParent(node)); 223 } 224 } 225 return END; 226 } 227 228 public DTMAxisIterator setStartNode(int node) { 229 if (_isRestartable) { 230 _source.setStartNode(_startNode = node); 231 return resetPosition(); 232 } 233 return this; 234 } 235 236 public void setMark() { 237 _source.setMark(); 238 } 239 240 public void gotoMark() { 241 _source.gotoMark(); 242 } 243 } 244 245 public MultiDOM(DOM main) { 246 _size = INITIAL_SIZE; 247 _free = 1; 248 _adapters = new DOM[INITIAL_SIZE]; 249 DOMAdapter adapter = (DOMAdapter)main; 250 _adapters[0] = adapter; 251 _main = adapter; 252 DOM dom = adapter.getDOMImpl(); 253 if (dom instanceof DTMDefaultBase) { 254 _dtmManager = ((DTMDefaultBase)dom).getManager(); 255 } 256 257 // %HZ% %REVISIT% Is this the right thing to do here? In the old 258 // %HZ% %REVISIT% version, the main document did not get added through 259 // %HZ% %REVISIT% a call to addDOMAdapter, which meant it couldn't be 260 // %HZ% %REVISIT% found by a call to getDocumentMask. The problem is 261 // %HZ% %REVISIT% TransformerHandler is typically constructed with a 262 // %HZ% %REVISIT% system ID equal to the stylesheet's URI; with SAX 263 // %HZ% %REVISIT% input, it ends up giving that URI to the document. 264 // %HZ% %REVISIT% Then, any references to document('') are resolved 265 // %HZ% %REVISIT% using the stylesheet's URI. 266 // %HZ% %REVISIT% MultiDOM.getDocumentMask is called to verify that 267 // %HZ% %REVISIT% a document associated with that URI has not been 268 // %HZ% %REVISIT% encountered, and that method ends up returning the 269 // %HZ% %REVISIT% mask of the main document, when what we really what 270 // %HZ% %REVISIT% is to read the stylesheet itself! 271 addDOMAdapter(adapter, false); 272 } 273 274 public int nextMask() { 275 return _free; 276 } 277 278 public void setupMapping(String[] names, String[] uris, int[] types, String[] namespaces) { 279 // This method only has a function in DOM adapters 280 } 281 282 public int addDOMAdapter(DOMAdapter adapter) { 283 return addDOMAdapter(adapter, true); 284 } 285 286 private int addDOMAdapter(DOMAdapter adapter, boolean indexByURI) { 287 // Add the DOM adapter to the array of DOMs 288 DOM dom = adapter.getDOMImpl(); 289 290 int domNo = 1; 291 int dtmSize = 1; 292 SuballocatedIntVector dtmIds = null; 293 if (dom instanceof DTMDefaultBase) { 294 DTMDefaultBase dtmdb = (DTMDefaultBase)dom; 295 dtmIds = dtmdb.getDTMIDs(); 296 dtmSize = dtmIds.size(); 297 domNo = dtmIds.elementAt(dtmSize-1) >>> DTMManager.IDENT_DTM_NODE_BITS; 298 } 299 else if (dom instanceof SimpleResultTreeImpl) { 300 SimpleResultTreeImpl simpleRTF = (SimpleResultTreeImpl)dom; 301 domNo = simpleRTF.getDocument() >>> DTMManager.IDENT_DTM_NODE_BITS; 302 } 303 304 if (domNo >= _size) { 305 int oldSize = _size; 306 do { 307 _size *= 2; 308 } while (_size <= domNo); 309 310 final DOMAdapter[] newArray = new DOMAdapter[_size]; 311 System.arraycopy(_adapters, 0, newArray, 0, oldSize); 312 _adapters = newArray; 313 } 314 315 _free = domNo + 1; 316 317 if (dtmSize == 1) { 318 _adapters[domNo] = adapter; 319 } 320 else if (dtmIds != null) { 321 int domPos = 0; 322 for (int i = dtmSize - 1; i >= 0; i--) { 323 domPos = dtmIds.elementAt(i) >>> DTMManager.IDENT_DTM_NODE_BITS; 324 _adapters[domPos] = adapter; 325 } 326 domNo = domPos; 327 } 328 329 // Store reference to document (URI) in hashtable 330 if (indexByURI) { 331 String uri = adapter.getDocumentURI(0); 332 _documents.put(uri, new Integer(domNo)); 333 } 334 335 // If the dom is an AdaptiveResultTreeImpl, we need to create a 336 // DOMAdapter around its nested dom object (if it is non-null) and 337 // add the DOMAdapter to the list. 338 if (dom instanceof AdaptiveResultTreeImpl) { 339 AdaptiveResultTreeImpl adaptiveRTF = (AdaptiveResultTreeImpl)dom; 340 DOM nestedDom = adaptiveRTF.getNestedDOM(); 341 if (nestedDom != null) { 342 DOMAdapter newAdapter = new DOMAdapter(nestedDom, 343 adapter.getNamesArray(), 344 adapter.getUrisArray(), 345 adapter.getTypesArray(), 346 adapter.getNamespaceArray()); 347 addDOMAdapter(newAdapter); 348 } 349 } 350 351 return domNo; 352 } 353 354 public int getDocumentMask(String uri) { 355 Integer domIdx = (Integer)_documents.get(uri); 356 if (domIdx == null) { 357 return(-1); 358 } else { 359 return domIdx.intValue(); 360 } 361 } 362 363 public DOM getDOMAdapter(String uri) { 364 Integer domIdx = (Integer)_documents.get(uri); 365 if (domIdx == null) { 366 return(null); 367 } else { 368 return(_adapters[domIdx.intValue()]); 369 } 370 } 371 372 public int getDocument() 373 { 374 return _main.getDocument(); 375 } 376 377 public DTMManager getDTMManager() { 378 return _dtmManager; 379 } 380 381 /** 382 * Returns singleton iterator containing the document root 383 */ 384 public DTMAxisIterator getIterator() { 385 // main source document @ 0 386 return _main.getIterator(); 387 } 388 389 public String getStringValue() { 390 return _main.getStringValue(); 391 } 392 393 public DTMAxisIterator getChildren(final int node) { 394 return _adapters[getDTMId(node)].getChildren(node); 395 } 396 397 public DTMAxisIterator getTypedChildren(final int type) { 398 return new AxisIterator(Axis.CHILD, type); 399 } 400 401 public DTMAxisIterator getAxisIterator(final int axis) { 402 return new AxisIterator(axis, NO_TYPE); 403 } 404 405 public DTMAxisIterator getTypedAxisIterator(final int axis, final int type) 406 { 407 return new AxisIterator(axis, type); 408 } 409 410 public DTMAxisIterator getNthDescendant(int node, int n, 411 boolean includeself) 412 { 413 return _adapters[getDTMId(node)].getNthDescendant(node, n, includeself); 414 } 415 416 public DTMAxisIterator getNodeValueIterator(DTMAxisIterator iterator, 417 int type, String value, 418 boolean op) 419 { 420 return(new NodeValueIterator(iterator, type, value, op)); 421 } 422 423 public DTMAxisIterator getNamespaceAxisIterator(final int axis, 424 final int ns) 425 { 426 DTMAxisIterator iterator = _main.getNamespaceAxisIterator(axis, ns); 427 return(iterator); 428 } 429 430 public DTMAxisIterator orderNodes(DTMAxisIterator source, int node) { 431 return _adapters[getDTMId(node)].orderNodes(source, node); 432 } 433 434 public int getExpandedTypeID(final int node) { 435 if (node != DTM.NULL) { 436 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getExpandedTypeID(node); 437 } 438 else { 439 return DTM.NULL; 440 } 441 } 442 443 public int getNamespaceType(final int node) { 444 return _adapters[getDTMId(node)].getNamespaceType(node); 445 } 446 447 public int getNSType(int node) 448 { 449 return _adapters[getDTMId(node)].getNSType(node); 450 } 451 452 public int getParent(final int node) { 453 if (node == DTM.NULL) { 454 return DTM.NULL; 455 } 456 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getParent(node); 457 } 458 459 public int getAttributeNode(final int type, final int el) { 460 if (el == DTM.NULL) { 461 return DTM.NULL; 462 } 463 return _adapters[el >>> DTMManager.IDENT_DTM_NODE_BITS].getAttributeNode(type, el); 464 } 465 466 public String getNodeName(final int node) { 467 if (node == DTM.NULL) { 468 return ""; 469 } 470 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeName(node); 471 } 472 473 public String getNodeNameX(final int node) { 474 if (node == DTM.NULL) { 475 return ""; 476 } 477 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeNameX(node); 478 } 479 480 public String getNamespaceName(final int node) { 481 if (node == DTM.NULL) { 482 return ""; 483 } 484 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNamespaceName(node); 485 } 486 487 public String getStringValueX(final int node) { 488 if (node == DTM.NULL) { 489 return ""; 490 } 491 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getStringValueX(node); 492 } 493 494 public void copy(final int node, SerializationHandler handler) 495 throws TransletException 496 { 497 if (node != DTM.NULL) { 498 _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler); 499 } 500 } 501 502 public void copy(DTMAxisIterator nodes, SerializationHandler handler) 503 throws TransletException 504 { 505 int node; 506 while ((node = nodes.next()) != DTM.NULL) { 507 _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler); 508 } 509 } 510 511 512 public String shallowCopy(final int node, SerializationHandler handler) 513 throws TransletException 514 { 515 if (node == DTM.NULL) { 516 return ""; 517 } 518 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].shallowCopy(node, handler); 519 } 520 521 public boolean lessThan(final int node1, final int node2) { 522 if (node1 == DTM.NULL) { 523 return true; 524 } 525 if (node2 == DTM.NULL) { 526 return false; 527 } 528 final int dom1 = getDTMId(node1); 529 final int dom2 = getDTMId(node2); 530 return dom1 == dom2 ? _adapters[dom1].lessThan(node1, node2) 531 : dom1 < dom2; 532 } 533 534 public void characters(final int textNode, SerializationHandler handler) 535 throws TransletException 536 { 537 if (textNode != DTM.NULL) { 538 _adapters[textNode >>> DTMManager.IDENT_DTM_NODE_BITS].characters(textNode, handler); 539 } 540 } 541 542 public void setFilter(StripFilter filter) { 543 for (int dom=0; dom<_free; dom++) { 544 if (_adapters[dom] != null) { 545 _adapters[dom].setFilter(filter); 546 } 547 } 548 } 549 550 public Node makeNode(int index) { 551 if (index == DTM.NULL) { 552 return null; 553 } 554 return _adapters[getDTMId(index)].makeNode(index); 555 } 556 557 public Node makeNode(DTMAxisIterator iter) { 558 // TODO: gather nodes from all DOMs ? 559 return _main.makeNode(iter); 560 } 561 562 public NodeList makeNodeList(int index) { 563 if (index == DTM.NULL) { 564 return null; 565 } 566 return _adapters[getDTMId(index)].makeNodeList(index); 567 } 568 569 public NodeList makeNodeList(DTMAxisIterator iter) { 570 int index = iter.next(); 571 if (index == DTM.NULL) { 572 return null; 573 } 574 iter.reset(); 575 return _adapters[getDTMId(index)].makeNodeList(iter); 576 } 577 578 public String getLanguage(int node) { 579 return _adapters[getDTMId(node)].getLanguage(node); 580 } 581 582 public int getSize() { 583 int size = 0; 584 for (int i=0; i<_size; i++) { 585 size += _adapters[i].getSize(); 586 } 587 return(size); 588 } 589 590 public String getDocumentURI(int node) { 591 if (node == DTM.NULL) { 592 node = DOM.NULL; 593 } 594 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getDocumentURI(0); 595 } 596 597 public boolean isElement(final int node) { 598 if (node == DTM.NULL) { 599 return false; 600 } 601 return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isElement(node)); 602 } 603 604 public boolean isAttribute(final int node) { 605 if (node == DTM.NULL) { 606 return false; 607 } 608 return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isAttribute(node)); 609 } 610 611 public int getDTMId(int nodeHandle) 612 { 613 if (nodeHandle == DTM.NULL) 614 return 0; 615 616 int id = nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS; 617 while (id >= 2 && _adapters[id] == _adapters[id-1]) { 618 id--; 619 } 620 return id; 621 } 622 623 public DOM getDTM(int nodeHandle) { 624 return _adapters[getDTMId(nodeHandle)]; 625 } 626 627 public int getNodeIdent(int nodeHandle) 628 { 629 return _adapters[nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeIdent(nodeHandle); 630 } 631 632 public int getNodeHandle(int nodeId) 633 { 634 return _main.getNodeHandle(nodeId); 635 } 636 637 public DOM getResultTreeFrag(int initSize, int rtfType) 638 { 639 return _main.getResultTreeFrag(initSize, rtfType); 640 } 641 642 public DOM getResultTreeFrag(int initSize, int rtfType, boolean addToManager) 643 { 644 return _main.getResultTreeFrag(initSize, rtfType, addToManager); 645 } 646 647 public DOM getMain() 648 { 649 return _main; 650 } 651 652 /** 653 * Returns a DOMBuilder class wrapped in a SAX adapter. 654 */ 655 public SerializationHandler getOutputDomBuilder() 656 { 657 return _main.getOutputDomBuilder(); 658 } 659 660 public String lookupNamespace(int node, String prefix) 661 throws TransletException 662 { 663 return _main.lookupNamespace(node, prefix); 664 } 665 666 // %HZ% Does this method make any sense here??? 667 public String getUnparsedEntityURI(String entity) { 668 return _main.getUnparsedEntityURI(entity); 669 } 670 671 // %HZ% Does this method make any sense here??? 672 public Hashtable getElementsWithIDs() { 673 return _main.getElementsWithIDs(); 674 } 675 }