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