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 }