View Javadoc
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         // 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 }