KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > dtm > ref > sax2dtm > SAX2RTFDTM


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: SAX2RTFDTM.java,v 1.9 2004/02/17 04:07:37 minchau Exp $
18  */

19 package org.apache.xml.dtm.ref.sax2dtm;
20
21 import javax.xml.transform.Source JavaDoc;
22
23 import org.apache.xml.dtm.DTM;
24 import org.apache.xml.dtm.DTMManager;
25 import org.apache.xml.dtm.DTMWSFilter;
26 import org.apache.xml.utils.IntStack;
27 import org.apache.xml.utils.IntVector;
28 import org.apache.xml.utils.StringVector;
29 import org.apache.xml.utils.XMLStringFactory;
30
31 import org.xml.sax.SAXException JavaDoc;
32
33 /**
34  * This is a subclass of SAX2DTM which has been modified to meet the needs of
35  * Result Tree Frameworks (RTFs). The differences are:
36  *
37  * 1) Multiple XML trees may be appended to the single DTM. This means
38  * that the root node of each document is _not_ node 0. Some code has
39  * had to be deoptimized to support this mode of operation, and an
40  * explicit mechanism for obtaining the Node Handle of the root node
41  * has been provided.
42  *
43  * 2) A stack of these documents is maintained, allowing us to "tail-prune" the
44  * most recently added trees off the end of the DTM as stylesheet elements
45  * (and thus variable contexts) are exited.
46  *
47  * PLEASE NOTE that this class may be _heavily_ dependent upon the
48  * internals of the SAX2DTM superclass, and must be maintained in
49  * parallel with that code. Arguably, they should be conditionals
50  * within a single class... but they have deen separated for
51  * performance reasons. (In fact, one could even argue about which is
52  * the superclass and which is the subclass; the current arrangement
53  * is as much about preserving stability of existing code during
54  * development as anything else.)
55  *
56  * %REVIEW% In fact, since the differences are so minor, I think it
57  * may be possible/practical to fold them back into the base
58  * SAX2DTM. Consider that as a future code-size optimization.
59  * */

60 public class SAX2RTFDTM extends SAX2DTM
61 {
62   /** Set true to monitor SAX events and similar diagnostic info. */
63   private static final boolean DEBUG = false;
64   
65   /** Most recently started Document, or null if the DTM is empty. */
66   private int m_currentDocumentNode=NULL;
67   
68   /** Tail-pruning mark: Number of nodes in use */
69   IntStack mark_size=new IntStack();
70   /** Tail-pruning mark: Number of data items in use */
71   IntStack mark_data_size=new IntStack();
72   /** Tail-pruning mark: Number of size-of-data fields in use */
73   IntStack mark_char_size=new IntStack();
74   /** Tail-pruning mark: Number of dataOrQName slots in use */
75   IntStack mark_doq_size=new IntStack();
76   /** Tail-pruning mark: Number of namespace declaration sets in use
77    * %REVIEW% I don't think number of NS sets is ever different from number
78    * of NS elements. We can probabably reduce these to a single stack and save
79    * some storage.
80    * */

81   IntStack mark_nsdeclset_size=new IntStack();
82   /** Tail-pruning mark: Number of naespace declaration elements in use
83    * %REVIEW% I don't think number of NS sets is ever different from number
84    * of NS elements. We can probabably reduce these to a single stack and save
85    * some storage.
86    */

87   IntStack mark_nsdeclelem_size=new IntStack();
88
89   /**
90    * Tail-pruning mark: initial number of nodes in use
91    */

92   int m_emptyNodeCount;
93
94   /**
95    * Tail-pruning mark: initial number of namespace declaration sets
96    */

97   int m_emptyNSDeclSetCount;
98
99   /**
100    * Tail-pruning mark: initial number of namespace declaration elements
101    */

102   int m_emptyNSDeclSetElemsCount;
103
104   /**
105    * Tail-pruning mark: initial number of data items in use
106    */

107   int m_emptyDataCount;
108
109   /**
110    * Tail-pruning mark: initial number of characters in use
111    */

112   int m_emptyCharsCount;
113
114   /**
115    * Tail-pruning mark: default initial number of dataOrQName slots in use
116    */

117   int m_emptyDataQNCount;
118   
119   public SAX2RTFDTM(DTMManager mgr, Source JavaDoc source, int dtmIdentity,
120                  DTMWSFilter whiteSpaceFilter,
121                  XMLStringFactory xstringfactory,
122                  boolean doIndexing)
123   {
124     super(mgr, source, dtmIdentity, whiteSpaceFilter,
125           xstringfactory, doIndexing);
126           
127     // NEVER track source locators for RTFs; they aren't meaningful. I think.
128
// (If we did track them, we'd need to tail-prune these too.)
129
//org.apache.xalan.processor.TransformerFactoryImpl.m_source_location;
130
m_useSourceLocationProperty=false;
131     m_sourceSystemId = (m_useSourceLocationProperty) ? new StringVector()
132                                                      : null;
133     m_sourceLine = (m_useSourceLocationProperty) ? new IntVector() : null;
134     m_sourceColumn = (m_useSourceLocationProperty) ? new IntVector() : null;
135
136     // Record initial sizes of fields that are pushed and restored
137
// for RTF tail-pruning. More entries can be popped than pushed, so
138
// we need this to mark the primordial state of the DTM.
139
m_emptyNodeCount = m_size;
140     m_emptyNSDeclSetCount = (m_namespaceDeclSets == null)
141                                  ? 0 : m_namespaceDeclSets.size();
142     m_emptyNSDeclSetElemsCount = (m_namespaceDeclSetElements == null)
143                                       ? 0 : m_namespaceDeclSetElements.size();
144     m_emptyDataCount = m_data.size();
145     m_emptyCharsCount = m_chars.size();
146     m_emptyDataQNCount = m_dataOrQName.size();
147   }
148   
149   /**
150    * Given a DTM, find the owning document node. In the case of
151    * SAX2RTFDTM, which may contain multiple documents, this returns
152    * the <b>most recently started</b> document, or null if the DTM is
153    * empty or no document is currently under construction.
154    *
155    * %REVIEW% Should we continue to report the most recent after
156    * construction has ended? I think not, given that it may have been
157    * tail-pruned.
158    *
159    * @param nodeHandle the id of the node.
160    * @return int Node handle of Document node, or null if this DTM does not
161    * contain an "active" document.
162    * */

163   public int getDocument()
164   {
165     return makeNodeHandle(m_currentDocumentNode);
166   }
167
168   /**
169    * Given a node handle, find the owning document node, using DTM semantics
170    * (Document owns itself) rather than DOM semantics (Document has no owner).
171    *
172    * (I'm counting on the fact that getOwnerDocument() is implemented on top
173    * of this call, in the superclass, to avoid having to rewrite that one.
174    * Be careful if that code changes!)
175    *
176    * @param nodeHandle the id of the node.
177    * @return int Node handle of owning document
178    */

179   public int getDocumentRoot(int nodeHandle)
180   {
181     for (int id=makeNodeIdentity(nodeHandle); id!=NULL; id=_parent(id)) {
182       if (_type(id)==DTM.DOCUMENT_NODE) {
183         return makeNodeHandle(id);
184       }
185     }
186
187     return DTM.NULL; // Safety net; should never happen
188
}
189   
190   /**
191    * Given a node identifier, find the owning document node. Unlike the DOM,
192    * this considers the owningDocument of a Document to be itself. Note that
193    * in shared DTMs this may not be zero.
194    *
195    * @param nodeIdentifier the id of the starting node.
196    * @return int Node identifier of the root of this DTM tree
197    */

198   protected int _documentRoot(int nodeIdentifier)
199   {
200     if(nodeIdentifier==NULL) return NULL;
201
202     for (int parent=_parent(nodeIdentifier);
203          parent!=NULL;
204          nodeIdentifier=parent,parent=_parent(nodeIdentifier))
205       ;
206    
207     return nodeIdentifier;
208   }
209
210   /**
211    * Receive notification of the beginning of a new RTF document.
212    *
213    * %REVIEW% Y'know, this isn't all that much of a deoptimization. We
214    * might want to consider folding the start/endDocument changes back
215    * into the main SAX2DTM so we don't have to expose so many fields
216    * (even as Protected) and carry the additional code.
217    *
218    * @throws SAXException Any SAX exception, possibly
219    * wrapping another exception.
220    * @see org.xml.sax.ContentHandler#startDocument
221    * */

222   public void startDocument() throws SAXException JavaDoc
223   {
224     // Re-initialize the tree append process
225
m_endDocumentOccured = false;
226     m_prefixMappings = new java.util.Vector JavaDoc();
227     m_contextIndexes = new IntStack();
228     m_parents = new IntStack();
229    
230     m_currentDocumentNode=m_size;
231     super.startDocument();
232   }
233  
234   /**
235    * Receive notification of the end of the document.
236    *
237    * %REVIEW% Y'know, this isn't all that much of a deoptimization. We
238    * might want to consider folding the start/endDocument changes back
239    * into the main SAX2DTM so we don't have to expose so many fields
240    * (even as Protected).
241    *
242    * @throws SAXException Any SAX exception, possibly
243    * wrapping another exception.
244    * @see org.xml.sax.ContentHandler#endDocument
245    * */

246   public void endDocument() throws SAXException JavaDoc
247   {
248     charactersFlush();
249
250     m_nextsib.setElementAt(NULL,m_currentDocumentNode);
251
252     if (m_firstch.elementAt(m_currentDocumentNode) == NOTPROCESSED)
253       m_firstch.setElementAt(NULL,m_currentDocumentNode);
254
255     if (DTM.NULL != m_previous)
256       m_nextsib.setElementAt(DTM.NULL,m_previous);
257
258     m_parents = null;
259     m_prefixMappings = null;
260     m_contextIndexes = null;
261
262     m_currentDocumentNode= NULL; // no longer open
263
m_endDocumentOccured = true;
264   }
265  
266
267   /** "Tail-pruning" support for RTFs.
268    *
269    * This function pushes information about the current size of the
270    * DTM's data structures onto a stack, for use by popRewindMark()
271    * (which see).
272    *
273    * %REVIEW% I have no idea how to rewind m_elemIndexes. However,
274    * RTFs will not be indexed, so I can simply panic if that case
275    * arises. Hey, it works...
276    * */

277   public void pushRewindMark()
278   {
279     if(m_indexing || m_elemIndexes!=null)
280       throw new java.lang.NullPointerException JavaDoc("Coding error; Don't try to mark/rewind an indexed DTM");
281
282     // Values from DTMDefaultBase
283
// %REVIEW% Can the namespace stack sizes ever differ? If not, save space!
284
mark_size.push(m_size);
285     mark_nsdeclset_size.push((m_namespaceDeclSets==null)
286                                    ? 0
287                                    : m_namespaceDeclSets.size());
288     mark_nsdeclelem_size.push((m_namespaceDeclSetElements==null)
289                                    ? 0
290                                    : m_namespaceDeclSetElements.size());
291    
292     // Values from SAX2DTM
293
mark_data_size.push(m_data.size());
294     mark_char_size.push(m_chars.size());
295     mark_doq_size.push(m_dataOrQName.size());
296   }
297  
298   /** "Tail-pruning" support for RTFs.
299    *
300    * This function pops the information previously saved by
301    * pushRewindMark (which see) and uses it to discard all nodes added
302    * to the DTM after that time. We expect that this will allow us to
303    * reuse storage more effectively.
304    *
305    * This is _not_ intended to be called while a document is still being
306    * constructed -- only between endDocument and the next startDocument
307    *
308    * %REVIEW% WARNING: This is the first use of some of the truncation
309    * methods. If Xalan blows up after this is called, that's a likely
310    * place to check.
311    *
312    * %REVIEW% Our original design for DTMs permitted them to share
313    * string pools. If there any risk that this might be happening, we
314    * can _not_ rewind and recover the string storage. One solution
315    * might to assert that DTMs used for RTFs Must Not take advantage
316    * of that feature, but this seems excessively fragile. Another, much
317    * less attractive, would be to just let them leak... Nah.
318    *
319    * @return true if and only if the pop completely emptied the
320    * RTF. That response is used when determining how to unspool
321    * RTF-started-while-RTF-open situations.
322    * */

323   public boolean popRewindMark()
324   {
325     boolean top=mark_size.empty();
326    
327     m_size=top ? m_emptyNodeCount : mark_size.pop();
328     m_exptype.setSize(m_size);
329     m_firstch.setSize(m_size);
330     m_nextsib.setSize(m_size);
331     m_prevsib.setSize(m_size);
332     m_parent.setSize(m_size);
333
334     m_elemIndexes=null;
335
336     int ds= top ? m_emptyNSDeclSetCount : mark_nsdeclset_size.pop();
337     if (m_namespaceDeclSets!=null) {
338       m_namespaceDeclSets.setSize(ds);
339     }
340
341     int ds1= top ? m_emptyNSDeclSetElemsCount : mark_nsdeclelem_size.pop();
342     if (m_namespaceDeclSetElements!=null) {
343       m_namespaceDeclSetElements.setSize(ds1);
344     }
345  
346     // Values from SAX2DTM - m_data always has a reserved entry
347
m_data.setSize(top ? m_emptyDataCount : mark_data_size.pop());
348     m_chars.setLength(top ? m_emptyCharsCount : mark_char_size.pop());
349     m_dataOrQName.setSize(top ? m_emptyDataQNCount : mark_doq_size.pop());
350
351     // Return true iff DTM now empty
352
return m_size==0;
353   }
354  
355   /** @return true if a DTM tree is currently under construction.
356    * */

357   public boolean isTreeIncomplete()
358   {
359     return !m_endDocumentOccured;
360   }
361 }
362
Popular Tags