MultiDOM.java revision 628:2bfaf29cc90b
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
24package com.sun.org.apache.xalan.internal.xsltc.dom;
25
26import com.sun.org.apache.xalan.internal.xsltc.DOM;
27import com.sun.org.apache.xalan.internal.xsltc.StripFilter;
28import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
29import com.sun.org.apache.xalan.internal.xsltc.TransletException;
30import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
31import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
32import com.sun.org.apache.xml.internal.dtm.DTM;
33import com.sun.org.apache.xml.internal.dtm.Axis;
34import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
35import com.sun.org.apache.xml.internal.dtm.DTMManager;
36import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase;
37import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
38import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector;
39
40import org.w3c.dom.Node;
41import org.w3c.dom.NodeList;
42
43/**
44 * @author Jacek Ambroziak
45 * @author Morten Jorgensen
46 * @author Erwin Bolwidt <ejb@klomp.org>
47 */
48public 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        // TODO: gather nodes from all DOMs ?
571        return _main.makeNodeList(iter);
572    }
573
574    public String getLanguage(int node) {
575        return _adapters[getDTMId(node)].getLanguage(node);
576    }
577
578    public int getSize() {
579        int size = 0;
580        for (int i=0; i<_size; i++) {
581            size += _adapters[i].getSize();
582        }
583        return(size);
584    }
585
586    public String getDocumentURI(int node) {
587        if (node == DTM.NULL) {
588            node = DOM.NULL;
589        }
590        return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getDocumentURI(0);
591    }
592
593    public boolean isElement(final int node) {
594        if (node == DTM.NULL) {
595            return false;
596        }
597        return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isElement(node));
598    }
599
600    public boolean isAttribute(final int node) {
601        if (node == DTM.NULL) {
602            return false;
603        }
604        return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isAttribute(node));
605    }
606
607    public int getDTMId(int nodeHandle)
608    {
609        if (nodeHandle == DTM.NULL)
610            return 0;
611
612        int id = nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS;
613        while (id >= 2 && _adapters[id] == _adapters[id-1]) {
614            id--;
615        }
616        return id;
617    }
618
619    public DOM getDTM(int nodeHandle) {
620        return _adapters[getDTMId(nodeHandle)];
621    }
622
623    public int getNodeIdent(int nodeHandle)
624    {
625        return _adapters[nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeIdent(nodeHandle);
626    }
627
628    public int getNodeHandle(int nodeId)
629    {
630        return _main.getNodeHandle(nodeId);
631    }
632
633    public DOM getResultTreeFrag(int initSize, int rtfType)
634    {
635        return _main.getResultTreeFrag(initSize, rtfType);
636    }
637
638    public DOM getResultTreeFrag(int initSize, int rtfType, boolean addToManager)
639    {
640        return _main.getResultTreeFrag(initSize, rtfType, addToManager);
641    }
642
643    public DOM getMain()
644    {
645        return _main;
646    }
647
648    /**
649     * Returns a DOMBuilder class wrapped in a SAX adapter.
650     */
651    public SerializationHandler getOutputDomBuilder()
652    {
653        return _main.getOutputDomBuilder();
654    }
655
656    public String lookupNamespace(int node, String prefix)
657        throws TransletException
658    {
659        return _main.lookupNamespace(node, prefix);
660    }
661
662    // %HZ% Does this method make any sense here???
663    public String getUnparsedEntityURI(String entity) {
664        return _main.getUnparsedEntityURI(entity);
665    }
666
667    // %HZ% Does this method make any sense here???
668    public Hashtable getElementsWithIDs() {
669        return _main.getElementsWithIDs();
670    }
671}
672