KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > mapper > storage > XMLBuilder


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 /*
24  * XMLBuilder.java
25  *
26  * Created on 12 mars 2001, 18:01
27  */

28
29 package org.xquark.mapper.storage;
30
31 import java.sql.SQLException JavaDoc;
32 import java.util.*;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.xml.sax.ContentHandler JavaDoc;
37 import org.xml.sax.ErrorHandler JavaDoc;
38 import org.xml.sax.SAXException JavaDoc;
39 import org.xml.sax.ext.LexicalHandler JavaDoc;
40 import org.xml.sax.helpers.AttributesImpl JavaDoc;
41 import org.xquark.mapper.RepositoryException;
42 import org.xquark.mapper.mapping.ColumnMapping;
43 import org.xquark.mapper.mapping.TableMapping;
44 import org.xquark.mapper.metadata.*;
45 import org.xquark.schema.*;
46 import org.xquark.schema.validation.ContentIterator;
47 import org.xquark.schema.validation.ValidationContextProvider;
48 import org.xquark.util.NamespaceContextStack;
49 import org.xquark.xml.xdbc.XMLDBCException;
50 import org.xquark.xpath.NodeKind;
51
52 /**
53  *
54  *
55  * <p>Generation is guided by the schema and indecisions are removed by
56  * document instance information (stored in the structure table).</p>
57  * @see org.xquark.mapper.XMLCollection
58  */

59 public abstract class XMLBuilder
60 implements RepositoryConstants
61 {
62     private static final String JavaDoc RCSRevision = "$Revision: 1.2 $";
63     private static final String JavaDoc RCSName = "$Name: $";
64
65     private static Log log = LogFactory.getLog(XMLBuilder.class);
66             
67     private final static String JavaDoc DEFAULT_PREFIX = "ns";
68     private final static short UNKNOWN = 0;
69     private final static short FOUND_ELEMENT = 1;
70     private final static short NIL_ELEMENT = 2;
71     private final static short MISSING_ELEMENT = 3;
72     
73      // @return -2 if not found, -1 if found without UOID. UOID else.
74
protected final static long NOT_FOUND = -3;
75     protected final static long TEXT_FOUND = -2;
76     protected final static long NO_UOID_FOUND = -1;
77     
78     private final static int INDENT_ARRAY_TAB_COUNT = 10;
79     private final static char[] INDENT_CHAR_ARRAY = {0xA,'\t','\t','\t','\t',
80                                                 '\t','\t','\t','\t','\t','\t'};
81     
82     protected PathSet pathSet;
83     
84     //
85
// Generation variables
86
//
87
private AttributesImpl JavaDoc attributes = new AttributesImpl JavaDoc();
88     
89     protected ContentHandler JavaDoc contentHandler = null;
90     protected LexicalHandler JavaDoc lexicalHandler = null;
91     protected ErrorHandler JavaDoc errorHandler = null;
92     protected boolean generateDBPrefix = false; // if true the algorithm generate unconditionnaly prefixes found uin the db
93
protected PrefixProvider prefixProvider;
94     
95     // database objects
96
protected TableExplorer tuplePool;
97     
98     protected _RepositoryCollection collection;
99     private int defaultMappingIndex;
100     private ColumnMapping defaultColumnMapping; // for text nodes
101
private SchemaManager schemaManager; // for xsi types access
102

103     /** To be used by document reconstruction */
104     protected XMLBuilder(_RepositoryCollection collection)
105     throws XMLDBCException
106     {
107         this.collection = collection;
108         schemaManager = collection.getRepositoryConnection().getSchemaManager();
109         CollectionMetadata metadata = collection.getMetadata();
110         pathSet = metadata.getPathSet();
111         defaultMappingIndex = metadata.getDefaultMappingIndex();
112         defaultColumnMapping = metadata.getDefaultMapping().getDefaultColumnMapping(null);
113     }
114     
115     /**
116      * @uoid negative if the UOID could not be determined by the caller
117      * @level element level stating to 1 for the root element
118      * @return the last UOID generated by the method
119      */

120     protected long browseBranch(long first, long last, long uoid, long anchor,
121                              MetadataIterator metaContext, int level, boolean mixedContext)
122     throws XMLDBCException, SQLException JavaDoc, SAXException JavaDoc
123     {
124         PathNode meta = metaContext.getPathNode();
125         short pid = meta.getPathID();
126         ElementInfoSet eltInfo = null;
127         boolean nil;
128         boolean textOnly = true;
129         long branchLast = (uoid < 0 ? first : uoid);
130         
131         if (log.isDebugEnabled())
132             log.debug("Entering browseBranch [path, first, last]=" + meta + ',' + first + ',' + last);
133         
134         //
135
// PROCESS the CURRENT PATH
136
//
137

138         // initialize variables for multivaluated iteration
139
nil = false;
140         eltInfo = new ElementInfoSet();
141         prefixProvider.push();
142         
143         // process struct (consume at least)
144
StructExplorer structRow = tuplePool.getStructNode();
145         switch (meta.getStorageMode())
146         {
147             case PathMetadata.POTENTIAL_STRUCT:
148                 if (structRow.isInRange(first, last, pid) // note: testing range is necessary for query result segmentation since potential
149
&& ((uoid < 0) || (structRow.getUOID() == uoid)))
150                 {
151                     anchor = uoid = first = structRow.getUOID();
152                     branchLast = last = structRow.getLast();
153                     structRow.fetchNextRow(); // consume struct node raw
154
}
155                 else if (uoid >= first) // model leaf
156
anchor = first = last = branchLast = uoid;
157                 else if (meta.isMixed())
158                 {
159                     Tuple dataTuple = tuplePool.get(defaultMappingIndex);
160                     if (dataTuple.getPathID() != pid)
161                         return first; // path missing
162
first = last = branchLast = anchor = uoid = dataTuple.getUOID();
163                 }
164                 eltInfo.setStatus(FOUND_ELEMENT);
165                 break;
166             case PathMetadata.STRUCT_ONLY:
167             case PathMetadata.DATA_AND_STRUCT:
168                 if (!structRow.isInRange(first, last, pid)) // note: testing range is necessary for query result segmentation since potential
169
return first; // path missing
170
eltInfo.setStatus(FOUND_ELEMENT);
171                 anchor = uoid = first = structRow.getUOID();
172                 last = branchLast = structRow.getLast();
173                 structRow.fetchNextRow(); // consume struct node raw
174
break;
175             case PathMetadata.DATA_ONLY:
176                 if (uoid < 0)
177                 {
178                     Tuple dataTuple = tuplePool.get(meta.getReadTableMapping().getTableMapping().getTableIndex());
179                     if (dataTuple.getPathID() != pid)
180                         return first; // path missing
181
uoid = dataTuple.getUOID();
182                 }
183                 eltInfo.setStatus(FOUND_ELEMENT);
184                 first = last = branchLast = anchor = uoid;
185                 break;
186             case PathMetadata.DISCARDED:
187                 break;
188             default:
189                 throw new RepositoryException(RepositoryException.CONSISTENCY_ERROR,
190                 "Metadata is corrupted for the collection "
191                 + collection.getCollectionName() + "(Unknow storage flag "
192                 + meta.getStorageMode() + " for pid " + meta.getPathID() + ")");
193         }
194         
195         processElement(metaContext, first, last, uoid, anchor, eltInfo);
196         
197         switch (eltInfo.getStatus())
198         {
199             case NIL_ELEMENT:
200                 eltInfo.generateStartElement(meta);
201                 break;
202                 
203             case FOUND_ELEMENT:
204             case UNKNOWN: // because query generation may start with a discarded node (need to check children)
205
//
206
// PROCESS the CHILDREN of CURRENT PATH
207
//
208
long childUOID = NO_UOID_FOUND;
209                 long lastChild = uoid;
210                 PathNode child = null;
211                 
212                 // use iterator if possible
213
if (meta.isChildrenPositionEnforced()) // use schema iterator
214
{
215                     ContentIterator it;
216                     // If type is superseded by an XSI declaration, use it for schema guided-iteration
217
if (eltInfo.getXSIType() == null)
218                         it = metaContext.getElementDeclaration().getType().childIterator();
219                     else
220                         it = eltInfo.getXSIType().childIterator();
221                     
222                     if (it != null)
223                     {
224                         ElementDeclaration eltDecl = null;
225                         long textUOID;
226                         List nextValidElements = it.nextValidElements(); // because a new list is built at each call
227
while ((nextValidElements != null) && (nextValidElements.size() != 0))
228                         {
229                             childUOID = Long.MAX_VALUE;
230                             eltDecl = null;
231                             textUOID = NOT_FOUND;
232                             // scan text nodes
233
if (meta.isMixed())
234                                 textUOID = scanTextNode(first, last, pid);
235                             
236                             // child selection
237
switch (nextValidElements.size())
238                             {
239                                 case 1:
240                                     eltDecl = (ElementDeclaration)nextValidElements.get(0);
241                                     if (eltDecl != null)
242                                     {
243                                         child = metaContext.getChild(eltDecl.getNamespace(), eltDecl.getName(), NodeKind.ELEMENT);
244                                         childUOID = checkOccurrence(lastChild + 1, last, anchor, child, eltInfo.getChildCount() + 1);
245                                     }
246                                     break;
247                                 default: // contains null, or optional, or multivaluated
248
// browse possible elements and use db to decide
249
Iterator walker = nextValidElements.iterator();
250                                     long foundUOID;
251                                     ElementDeclaration potentialDecl = null;
252                                     while (walker.hasNext())
253                                     {
254                                         potentialDecl = (ElementDeclaration)walker.next();
255                                         if (potentialDecl == null) // ending element is possible
256
continue;
257                                         child = metaContext.getChild(potentialDecl.getNamespace(), potentialDecl.getName(), NodeKind.ELEMENT);
258                                         if (child != null)
259                                         {
260                                             foundUOID = checkOccurrence(lastChild + 1, last, anchor, child, eltInfo.getChildCount() + 1);
261                                             if((foundUOID != NOT_FOUND) && ((foundUOID < childUOID) || (childUOID == NO_UOID_FOUND)))
262                                             {
263                                                 if (foundUOID == NO_UOID_FOUND) // UOID not found
264
{
265                                                     if (eltDecl == null)
266                                                     {
267                                                         childUOID = foundUOID;
268                                                         eltDecl = potentialDecl;
269                                                     }
270                                                     break; // if a node is discarded, the iterator gives the order
271
}
272                                                 else // a smaller UOID is found
273
{
274                                                     childUOID = foundUOID;
275                                                     eltDecl = potentialDecl;
276                                                 }
277                                             }
278                                         }
279                                     }
280                                     break;
281                             }
282                             if ((textUOID != NOT_FOUND)
283                             && ((textUOID < childUOID) || (childUOID == NOT_FOUND)))
284                             {
285                                 eltInfo.generateStartElement(meta);
286                                 eltInfo.generateTextNode();
287                                 continue; // start again iteration because text node could hide the lowest subelement
288
}
289                             
290                             if (eltDecl == null) // no declaration found
291
break;
292                             
293                             eltInfo.generateStartElement(meta);
294                             
295                             //start It, push iterator,
296
eltInfo.flushExtraData(!mixedContext, true);
297                             if (!mixedContext)
298                                 indent(level);
299                             textOnly = false;
300                             metaContext.push(eltDecl.getNamespace(), eltDecl.getName());
301                             try {
302                                 it.startElement(eltDecl.getNamespace(), eltDecl.getName());
303                                 lastChild = browseBranch(first, last, childUOID, anchor,
304                                 metaContext, level + 1, mixedContext || metaContext.getPathNode().isMixed());
305                                 it.endElement(eltDecl.getNamespace(), eltDecl.getName());
306                                 nextValidElements = it.nextValidElements();
307                             }
308                             catch (SchemaException e) {
309                                 throw new RuntimeException JavaDoc("Error while iterating through schema: " + e.getMessage());
310                             }
311                             metaContext.pop();
312                             eltInfo.incChildCount(); // must be done before generateTextNode()
313
processExtraData(anchor, pid, eltInfo);
314                         }
315                     }
316                 }
317                 else // use db info (OID and extra)
318
{
319                     // child selection
320
while (((childUOID = scanChild(lastChild + 1, last, anchor, metaContext, eltInfo.getChildCount() + 1)) > NOT_FOUND)
321                             || !eltInfo.extraFlushed())
322                     {
323                         eltInfo.generateStartElement(meta);
324                         if (childUOID == NOT_FOUND)
325                             eltInfo.flushExtraData(!mixedContext, true);
326                         else if (childUOID == TEXT_FOUND)
327                             eltInfo.generateTextNode();
328                         else
329                         {
330                             eltInfo.flushExtraData(!mixedContext, true);
331                             if ((pid != ROOT_PATH_ID) && !mixedContext)
332                                 indent(level);
333                             textOnly = false;
334                             lastChild = browseBranch(first, last, childUOID, anchor,
335                             metaContext, level + 1, mixedContext || metaContext.getPathNode().isMixed());
336                             metaContext.pop();
337                             eltInfo.incChildCount(); // must be done before generateTextNode()
338
}
339                         processExtraData(anchor, pid, eltInfo);
340                     }
341                     // Flush remaining extra-data that may could not be positioned because of a wrong offset (normalization)
342
if (eltInfo.hasExtraData())
343                     {
344                         eltInfo.generateStartElement(meta);
345                         eltInfo.flushExtraData(!mixedContext, false); // purge
346
}
347                 }
348                 break;
349                 
350             default: // missing
351
return first;
352         }
353         
354         // for the case no child node has been found but start element must be generated
355
if (eltInfo.leafElementButNotMissing())
356             eltInfo.generateStartElement(meta);
357         
358         
359         // generate endElement
360
if (eltInfo.elementGenerated())
361         {
362             eltInfo.flushExtraData(!mixedContext, true);
363             if (!textOnly && !mixedContext)
364                 indent(level - 1);
365             contentHandler.endElement(
366             meta.getNamespace() == null ? "" : meta.getNamespace(),
367             meta.getLocalName(),
368             "");
369             eltInfo.generateEndPrefix();
370             
371             // process fetchNextRow for elements
372
if (meta.getTableMappings() != null)
373             {
374                 Iterator it = meta.getTableMappings().iterator();
375                 TableMapping refTableMapping = null, tm = null;
376                 if (meta.getReadColumnMapping() != null)
377                     refTableMapping = meta.getReadColumnMapping().getTableMapping();
378                 
379                 while (it.hasNext())
380                 {
381                     tm = (TableMapping)it.next();
382                     // Do not consume ref column mapping if already consumed
383
if (!tm.equals(refTableMapping))
384                         tuplePool.get(tm.getTableIndex()).fetchNextRow();
385                 }
386             }
387         }
388         prefixProvider.pop();
389         
390         if (log.isDebugEnabled())
391             log.debug("Exiting browseBranch [path]=" + meta);
392         return branchLast;
393     }
394    
395     /** Retrieve child info from the database without consuming tuples.
396      * Used by schemaless iteration.
397      * @return -2 if not found, -1 if found without UOID. UOID else.
398      */

399     private long scanChild(long first, long last, long anchor,
400                 MetadataIterator metaContext, int pos)
401                 throws SQLException JavaDoc, RepositoryException
402     {
403         short structPID = -1;
404         short dataPID = -1;
405         long structUOID = Long.MAX_VALUE;
406         long dataUOID = Long.MAX_VALUE;
407         short wPID, pid = metaContext.getPathMetadata().getPathID();
408         
409         // try first to find extra-data attached to the current node
410
// positioning info is retrieved first because of query ordering for
411
// the extra table.
412
if ((tuplePool.getExtraNode().getAnchor() == anchor)
413             && (tuplePool.getExtraNode().getType() >= NodeKind.ELEMENT)
414             && (tuplePool.getExtraNode().getPosition() == pos)) // TO CHECK: is it necessary to check the path found is a child ?
415
{
416             metaContext.push(tuplePool.getExtraNode().getPath());
417             return NO_UOID_FOUND;
418         }
419         else // search for the UOID in the struct and then in the data tables
420
{
421             // look in the struct table
422
StructExplorer structNode = null;
423             
424             if (tuplePool.getStructNode().isInRange(first, last))
425                 structNode = tuplePool.getStructNode();
426             
427             // look in the data tables but take if inferior to struct
428
Tuple nextDataTuple = tuplePool.pollData(
429                                 metaContext.getPathMetadata().getBuildMappings(),
430                                 first,
431                                 last
432                                 );
433             
434             if (structNode != null)
435             {
436                 wPID = structNode.getPath();
437                 if (wPID >= 0)
438                 {
439                     PathNode structChild = pathSet.get(wPID);
440                     if (((PathNode)structChild.getParent()).getPathID() == pid)
441                     {
442                         structUOID = structNode.getUOID();
443                         structPID = wPID;
444                     }
445                 }
446             }
447             
448             if (nextDataTuple != null)
449             {
450                 // text node found
451
if (metaContext.getPathMetadata().isMixed()
452                     && (nextDataTuple.getMapping().getTableIndex() == defaultMappingIndex)
453                     && (nextDataTuple.getPathID() == pid)) // for TEXT nodes minus path may be is used
454
return TEXT_FOUND;
455
456                 wPID = nextDataTuple.getPathID();
457                 if (wPID >= 0)
458                 {
459                     PathNode dataChild = pathSet.get(wPID); // may return a negative value if rs exhausted
460
if (((PathNode)dataChild.getParent()).getPathID() == pid)
461                     {
462                         dataUOID = nextDataTuple.getUOID();
463                         dataPID = wPID;
464                     }
465                  }
466             }
467         }
468         // take the smallest of potential childs
469
long childUOID = structUOID;
470         short childPID = structPID;
471         
472         if (dataUOID < childUOID)
473         {
474             childUOID = dataUOID;
475             childPID = dataPID;
476         }
477         
478         // update context
479
if (childUOID != Long.MAX_VALUE)
480         {
481              metaContext.push(childPID);
482              return childUOID;
483         }
484         else
485             return NOT_FOUND;
486     }
487     
488     /** Check in the database if a node exists without consuming tuples.
489      * Used by schema iteration.
490      * @return -2 if not found, -1 if found without UOID. UOID else.
491      */

492     private long checkOccurrence(long first, long last, long anchor,
493                     PathNode node, int pos)
494                     throws SQLException JavaDoc, XMLDBCException
495     {
496         long nodeUOID = NOT_FOUND;
497                 
498         // try first to find extra-data attached to the current node
499
// positioning info is retrieved first because of query ordering for
500
// the extra table.
501
if ((tuplePool.getExtraNode().getAnchor() == anchor)
502         && (tuplePool.getExtraNode().getPath() == node.getPathID())
503         && (tuplePool.getExtraNode().getType() >= NodeKind.ELEMENT))
504         {
505             if (tuplePool.getExtraNode().getPosition() == pos)
506                 nodeUOID = NO_UOID_FOUND;
507             else
508                 nodeUOID = NOT_FOUND;
509         }
510         else
511             nodeUOID = getElementUOID(first, last, node);
512         return nodeUOID;
513     }
514     
515     /** Retrieves the potential text node UOID.
516      * Used by schema iteration.
517      * @return -2 if not found, . UOID else.
518      */

519     private long scanTextNode(long first, long last, short parentPID)
520                     throws SQLException JavaDoc
521     {
522         long textNodeUOID = NOT_FOUND;
523         
524         // text node found
525
Tuple defaultTuple = tuplePool.get(defaultMappingIndex);
526         if (defaultTuple.isInRangeAbs(first, last , parentPID)) // for TEXT nodes minus path may be used
527
textNodeUOID = defaultTuple.getUOID();
528         
529         return textNodeUOID;
530     }
531     /** Retrieves the element UOID.
532      * Used by schema iteration.
533      * @return -2 if not found, -1 if found without UOID. UOID else.
534      */

535     protected long getElementUOID(long first, long last, PathNode node)
536                     throws SQLException JavaDoc, XMLDBCException
537     {
538         long nodeUOID = NOT_FOUND;
539         Tuple dataTuple;
540         
541         // try first to find extra-data attached to the current node
542
// positioning info is retrieved first because of query ordering for
543
// the extra table.
544
switch (node.getStorageMode())
545         {
546             case PathMetadata.POTENTIAL_STRUCT:
547                 // check in struct
548
if (tuplePool.getStructNode().isInRange(first, last, node.getPathID()))
549                     nodeUOID = tuplePool.getStructNode().getUOID();
550                 
551                 // check in data and take if smaller
552
dataTuple = tuplePool.get(defaultMappingIndex);
553                 if ((dataTuple != null) // may be null in query reconstruction
554
&& dataTuple.isInRangeAbs(first, last, node.getPathID())
555                 && ((nodeUOID < 0) || (dataTuple.getUOID() < nodeUOID)))
556                     nodeUOID = dataTuple.getUOID();
557                 break;
558                 
559             case PathMetadata.DATA_ONLY:
560                 // check in data (node must be associated to a tuple else would be discarded)
561
dataTuple = tuplePool.get(node.getReadTableMapping().getTableMapping().getTableIndex());
562                 if (dataTuple.isInRangeAbs(first, last, node.getPathID()))
563                     nodeUOID = dataTuple.getUOID();
564                 break;
565                 
566             case PathMetadata.DATA_AND_STRUCT:
567                 // check in struct
568
if (tuplePool.getStructNode().isInRange(first, last, node.getPathID()))
569                     nodeUOID = tuplePool.getStructNode().getUOID();
570                 else if (node.getReadTableMapping() != null) // for instance if mixed with children
571
{
572                     // check in data (node must be associated to a tuple else would be discarded)
573
dataTuple = tuplePool.get(node.getReadTableMapping().getTableMapping().getTableIndex());
574                     if (dataTuple.isInRangeAbs(first, last, node.getPathID()))
575                         nodeUOID = dataTuple.getUOID();
576                 }
577                 break;
578             case PathMetadata.STRUCT_ONLY:
579                 // check in struct
580
if (tuplePool.getStructNode().isInRange(first, last, node.getPathID()))
581                     nodeUOID = tuplePool.getStructNode().getUOID();
582                 break;
583                 
584             case PathMetadata.DISCARDED:
585                 // the null column case or DISCARDED because not optional
586
if (node.getReadColumnMapping() == null)
587                     nodeUOID = NO_UOID_FOUND; // discarded because intermediate mandatory node
588
else if (isMappedValueNull(node))
589                 {
590                     if (node.isNilImplicit())
591                         nodeUOID = NO_UOID_FOUND; // implicit nil (else an extra node would have been found
592
}
593                 else
594                     nodeUOID = NO_UOID_FOUND;
595                 break;
596             default:
597                 throw new RepositoryException(RepositoryException.CONSISTENCY_ERROR,
598                 "Metadata is corrupted for the collection "
599                 + collection.getCollectionName() + "(Unknow storage flag "
600                 + node.getStorageMode() + " for pid " + node.getPathID() + ")");
601         }
602         return nodeUOID;
603     }
604     
605     
606     /** generate all the events attached to that specific element path. DO NOT PROCESS
607      * SUBPATHS ! Note: struct is consumed (multivaluated process out of method by caller).
608      * perform startElement and startPrefix but not end...
609      * @param first UOID of deepest ancestor-or-self having a struct tuple
610      * @param last range last of deepest ancestor-or-self having a struct tuple
611      */

612     private void processElement(MetadataIterator metaContext, long first,
613                                 long last, long uoid, long anchor,
614                                 ElementInfoSet eltInfo)
615     throws XMLDBCException, SQLException JavaDoc, SAXException JavaDoc
616     {
617         PathNode wPath = metaContext.getPathNode();
618         short eltPID = wPath.getPathID();
619         
620         // process extra-data (ns prefixes, xsi atts, comments, PI...)
621
if (processExtraData(anchor, eltPID, eltInfo))
622             eltInfo.setStatus(NIL_ELEMENT);
623         
624         // generate prefix mapping if not taken from database and not declared at superior level
625
String JavaDoc nsUri = wPath.getNamespace();
626         if ((nsUri!= null) && !generateDBPrefix)
627         {
628             String JavaDoc pfx = prefixProvider.getPrefix(nsUri);
629             if (pfx == null)
630             {
631                 pfx = prefixProvider.getGeneratedPrefix(wPath);
632                 eltInfo.generateStartPrefixMapping(pfx, nsUri);
633             }
634         }
635       
636         if (eltPID == ROOT_PATH_ID)
637         {
638             // process root extra-nodes but not startElement
639
eltInfo.flushExtraData(true, true);
640             eltInfo.setStatus(FOUND_ELEMENT);
641             return;
642         }
643         
644         // attributes without tuples : browse path node attributes
645
Collection children = metaContext.getPathNode().getChildren();
646         if (children != null)
647         {
648             String JavaDoc value;
649             Iterator it = children.iterator();
650             
651             while (it.hasNext())
652             {
653                 wPath = (PathNode)it.next();
654                 if (wPath.getType() != NodeKind.ATTRIBUTE)
655                     continue;
656                 
657                 if (wPath.getReadTableMapping() == null) // tuple should be present
658
{
659                     value = getMappedValue(wPath, first, first, true, false, false);
660                     if (value != null)
661                         attributes.addAttribute(wPath.getNamespace() == null ? "" : wPath.getNamespace(),
662                         wPath.getLocalName(), "", ATTRIBUTE_TYPES[7], value);
663                 }
664             }
665         }
666         // Process the column mapping nil without extra-tuple (simple column mapping):
667
// need to anticipate the column mapping processing to see if null
668
wPath = metaContext.getPathNode();
669
670         if ((eltInfo.getStatus() != NIL_ELEMENT)
671             && ((wPath.getReadColumnMapping() != null) || wPath.isMixed()))
672         {
673             // store element character data
674
eltInfo.setValue(getElementCharData(wPath, uoid, eltInfo));
675             if (eltInfo.getValue() == null)
676             {
677                 if (wPath.isNilImplicit())
678                 {
679                     attributes.addAttribute(
680                     SchemaConstants.XSI_URI,
681                     SchemaConstants.XSI_NIL_ATTR,
682                     "",
683                     ATTRIBUTE_TYPES[7],
684                     SchemaConstants.TRUE_VALUE
685                     );
686                     eltInfo.setStatus(NIL_ELEMENT);
687                 }
688                 else if (eltInfo.getStatus() == UNKNOWN) // Discarded node
689
eltInfo.setStatus(MISSING_ELEMENT);
690             }
691             else
692                 eltInfo.setStatus(FOUND_ELEMENT);
693         }
694         
695         // generate now attributes with table mapping (OID allocated)
696
// do it after fetching element value !
697
processAttributes(first, last, metaContext);
698                 
699     }
700     
701     private boolean processExtraData(long anchor, short eltPID,
702                                     ElementInfoSet eltInfo)
703     throws SQLException JavaDoc, SAXException JavaDoc
704     {
705         boolean nil = false;
706         ExtraDataExplorer extraNodeBrowser = tuplePool.getExtraNode();
707         while ((extraNodeBrowser.getRowNum() > eltInfo.getLastRowNum())
708                 && (extraNodeBrowser.getPath() == eltPID)
709                 && (extraNodeBrowser.getUOID() == anchor)
710                 ||
711                 ((eltPID == ROOT_PATH_ID) && (extraNodeBrowser.getPath() == ROOT_PATH_ID))
712                 )
713         {
714             switch (extraNodeBrowser.getType())
715             {
716                 case NodeKind.NAMESPACE:
717                     String JavaDoc data = extraNodeBrowser.getData(); // "{" + uri + "}" + prefix
718
int i = data.indexOf('}');
719                     String JavaDoc pfx = data.substring(i+1);
720                     String JavaDoc uri = data.substring(1, i);
721                     if (prefixProvider.declarePrefix(pfx, uri) || generateDBPrefix) // generate it in query reconstruction if no defined in query
722
eltInfo.generateStartPrefixMapping(pfx, uri);
723                     break;
724                 case NodeKind.PI:
725                 case NodeKind.COMMENT:
726                 case START_CDATA_SECTION:
727                 case END_CDATA_SECTION:
728                     eltInfo.addNode(extraNodeBrowser.copyNode());
729                     break;
730                 case XSI_NIL:
731                     attributes.addAttribute(
732                         SchemaConstants.XSI_URI,
733                         SchemaConstants.XSI_NIL_ATTR,
734                         "",
735                         ATTRIBUTE_TYPES[7],
736                         extraNodeBrowser.getData()
737                         );
738                     nil = extraNodeBrowser.isNil();
739                     break;
740                 case XSI_NO_NAMESPACE_SCHEMA_LOCATION:
741                     attributes.addAttribute(
742                         SchemaConstants.XSI_URI,
743                         SchemaConstants.XSI_NO_NAMESPACE_SCHEMA_LOCATION_ATTR,
744                         "",
745                         ATTRIBUTE_TYPES[7],
746                         extraNodeBrowser.getData()
747                         );
748                     break;
749                 case XSI_SCHEMA_LOCATION:
750                     attributes.addAttribute(
751                         SchemaConstants.XSI_URI,
752                         SchemaConstants.XSI_SCHEMA_LOCATION_ATTR,
753                         "",
754                         ATTRIBUTE_TYPES[7],
755                         extraNodeBrowser.getData()
756                         );
757                     break;
758                 case XSI_TYPE:
759                     String JavaDoc typeString = extraNodeBrowser.getData();
760                     String JavaDoc nsURI = null, localName = null;
761                     int bracket1 = typeString.indexOf('{');
762                     int bracket2 = typeString.indexOf('}');
763                     nsURI = typeString.substring(bracket1 + 1, bracket2 - bracket1);
764                     localName = typeString.substring(bracket2 + 1);
765                     
766                     eltInfo.setXSIType(schemaManager.getType(nsURI, localName));
767                     attributes.addAttribute(
768                         SchemaConstants.XSI_URI,
769                         SchemaConstants.XSI_TYPE_ATTR,
770                         "",
771                         ATTRIBUTE_TYPES[7],
772                         schemaManager.getQNameType().toXMLString(typeString, prefixProvider)
773                         );
774                     break;
775                 // change --> comments
776
// case NodeKind.ELEMENT:
777
// // position or occurence without xsi
778
// break;
779
default:
780                     // not expected : ignore
781
}
782             eltInfo.setExtraRowNum(extraNodeBrowser.getRowNum());
783             extraNodeBrowser.fetchNextRow();
784         }
785         return nil;
786     }
787
788     /**
789      * generate attributes with table mapping (OID allocated) for a particular
790      * range.
791      */

792     
793     private void processAttributes(long first, long last, MetadataIterator metaContext)
794     throws XMLDBCException, SQLException JavaDoc
795     {
796         // WARNING ! : because of OR5 : attributes are stored only in data tables
797
Tuple electedTuple = null;
798         PathNode attNode;
799         String JavaDoc value;
800         Collection mappingSubset = metaContext.getPathMetadata().getBuildMappings();
801         short eltPID = metaContext.getPathMetadata().getPathID();
802         
803         // loop till out of "range"
804
while ((electedTuple = tuplePool.pollData(mappingSubset, first + 1, last)) != null)
805         {
806             attNode = metaContext.getPathNode(electedTuple.getPathID());
807             // could check the attribute type and that it is attached to the right element
808
if ((attNode.getType() != org.xquark.xpath.NodeKind.ATTRIBUTE)
809             || (((PathNode)attNode.getParent()).getPathID() != eltPID))
810                 break;
811             
812             value = getMappedValue(attNode, first, last, false, true, false);
813             if (value != null) // not missing (optional)
814
{
815                 attributes.addAttribute(attNode.getNamespace() == null ? "" : attNode.getNamespace(),
816                 attNode.getLocalName(), "", ATTRIBUTE_TYPES[7], value);
817             }
818         }
819     }
820     
821     private boolean isMappedValueNull(PathMetadata node)
822     throws SQLException JavaDoc, XMLDBCException
823     {
824         boolean ret = false;
825         ColumnMapping column = node.getReadColumnMapping();
826         if (column != null) // no mapping
827
{
828             Tuple tuple = tuplePool.get(column.getTableIndex());
829             if (tuple.getValue(column, node.getDeclaration(), prefixProvider) == null)
830                 ret = true;
831         }
832         return ret;
833     }
834     
835     /**
836      *
837      */

838     protected String JavaDoc getMappedValue(PathMetadata node, long first, long last,
839                     boolean checkRange, boolean lookup, boolean systematic)
840     throws SQLException JavaDoc, XMLDBCException
841     {
842         String JavaDoc ret =null;
843         ColumnMapping column = node.getReadColumnMapping();
844         if (column != null) // no mapping
845
{
846             Tuple tuple = tuplePool.get(column.getTableIndex());
847             if (!checkRange || tuple.isInRange(first, last))
848                 ret = tuple.getValue(column, node.getDeclaration(), prefixProvider);
849             if (lookup && (systematic || (tuple.getPathID() == node.getPathID())))
850                 tuple.fetchNextRow();
851         }
852         return ret;
853     }
854     
855     /**
856      * returns the value only if the table path OID fits the tuple one.
857      * performs lookup if table path is node path
858      * Used for simple mapping.
859      */

860     private String JavaDoc getElementCharData(PathMetadata node, long eltUOID,
861     ElementInfoSet eltInfo)
862     throws SQLException JavaDoc, XMLDBCException
863     {
864         String JavaDoc ret = null;
865         ColumnMapping column = node.getReadColumnMapping();
866         if (column == null)
867             column = node.getTextColumnMapping();
868         PathMetadata tableNode = node.getTableMappingPath();
869         Tuple tuple = tuplePool.get(column.getTableIndex());
870         if (((eltUOID < 0) || (tuple.getUOID() == eltUOID))
871         && (tuple.getPathID() == (int)tableNode.getPathID()))
872         {
873             ret = tuple.getValue(column, node.getDeclaration(), prefixProvider);
874             if (tableNode.getPathID() == node.getPathID())
875                 tuple.fetchNextRow();
876         }
877         return ret;
878     }
879     
880     public void close() throws RepositoryException
881     {
882         if (tuplePool != null)
883         {
884             try
885             {
886                 tuplePool.close();
887                 tuplePool = null;
888                 pathSet = null;
889                 attributes = null;
890                 prefixProvider = null;
891                 collection = null;
892                 contentHandler = null;
893                 lexicalHandler = null;
894                 errorHandler = null;
895             }
896             catch (SQLException JavaDoc e)
897             {
898                 throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while freeing ressources", e);
899             }
900         }
901     }
902     
903     public void reset() throws RepositoryException, SQLException JavaDoc
904     {
905         // TO DO : Reset method metaContext;
906
attributes.clear();
907         tuplePool.reset();
908         prefixProvider.clear();
909     }
910     
911     /** Release handlers.
912      * @throws RepositoryException an application exception
913      */

914     public void unPlug()
915     {
916         contentHandler = null;
917         lexicalHandler = null;
918         errorHandler = null;
919     }
920     
921     
922     private void indent(int indent) throws SAXException JavaDoc
923     {
924         int quotient = indent/INDENT_ARRAY_TAB_COUNT;
925         
926         if (quotient == 0) // one array is enough (include eol)
927
contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 0, indent + 1);
928         else
929         {
930             // generate 1st array of tabs with initial eol
931
contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 0, INDENT_ARRAY_TAB_COUNT + 1);
932             for (int i = 2; i <= quotient; i++)
933             {
934                 contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 1, INDENT_ARRAY_TAB_COUNT);
935             }
936             int remainder = indent%INDENT_ARRAY_TAB_COUNT;
937             if (remainder > 0)
938                 contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 1, remainder);
939         }
940     }
941     
942     ////////////////////////////////////////////////////////////////////////////////
943
// INNER CLASSES
944
////////////////////////////////////////////////////////////////////////////////
945

946     protected class ElementInfoSet
947     {
948         private ArrayList nodesToInsert = new ArrayList(2);
949         private int childCount = 0;
950         private int charCount = 0;
951         private String JavaDoc value = null;
952         private boolean notGenerated = true;
953         private boolean extraFlushed = false;
954         private short status = UNKNOWN;
955         private short lastNum = -1;
956         private List prefixes = new ArrayList(2);
957         private org.xquark.schema.Type xsiType = null;
958
959         void addNode(ExtraNode node)
960         {
961             nodesToInsert.add(node);
962             extraFlushed = false;
963         }
964         void clear()
965         {
966             nodesToInsert.clear();
967             charCount = 0;
968             lastNum = -1;
969             value = null;
970             status = UNKNOWN;
971             notGenerated = true;
972             xsiType = null;
973             extraFlushed = false;
974         }
975         
976         void generateStartPrefixMapping(String JavaDoc pfx, String JavaDoc uri)
977         throws SAXException JavaDoc
978         {
979             prefixes.add(pfx);
980             contentHandler.startPrefixMapping(pfx, uri);
981         }
982         
983         void generateEndPrefix()
984         throws SAXException JavaDoc
985         {
986             int prefixCount = prefixes.size();
987             String JavaDoc pfx;
988             for (int i = 0; i < prefixCount; i++)
989             {
990                 pfx = (String JavaDoc)prefixes.get(i);
991                 contentHandler.endPrefixMapping(pfx);
992             }
993         }
994         
995         void setValue(String JavaDoc value)
996         {
997             this.value = value;
998         }
999         
1000        void setXSIType(org.xquark.schema.Type type)
1001        {
1002            xsiType = type;
1003        }
1004        
1005        org.xquark.schema.Type getXSIType()
1006        {
1007            return xsiType;
1008        }
1009        
1010        String JavaDoc getValue()
1011        {
1012            return value;
1013        }
1014        
1015        boolean hasValue()
1016        {
1017            return value != null;
1018        }
1019        
1020        boolean elementGenerated()
1021        {
1022            return !notGenerated;
1023        }
1024        
1025        boolean extraFlushed()
1026        {
1027            return extraFlushed;
1028        }
1029        
1030        boolean hasExtraData()
1031        {
1032            return nodesToInsert.size() != 0;
1033        }
1034        
1035        boolean leafElementButNotMissing()
1036        {
1037            return (childCount == 0) && (
1038                                            (status != MISSING_ELEMENT)
1039                                            || (value != null)
1040                                            || (attributes.getLength() != 0)
1041                                            );
1042        }
1043        
1044        void setStatus(short status)
1045        {
1046            this.status = status;
1047        }
1048        
1049        short getStatus()
1050        {
1051            return status;
1052        }
1053        
1054        void incChildCount()
1055        {
1056            childCount++;
1057        }
1058        
1059        int getChildCount()
1060        {
1061            return childCount;
1062        }
1063        
1064        void setExtraRowNum(short rowNum)
1065        {
1066            lastNum = rowNum;
1067        }
1068        
1069        short getLastRowNum()
1070        {
1071            return lastNum;
1072        }
1073        
1074        void generateStartElement(PathNode path)
1075        throws RepositoryException, SAXException JavaDoc
1076        {
1077            if (notGenerated && (path.getPathID() != ROOT_PATH_ID))
1078            {
1079                // start element (if OID IN DATA ? or NIL or extraTuple)
1080
contentHandler.startElement(
1081                path.getNamespace() == null ? "" : path.getNamespace(),
1082                path.getLocalName(),
1083                "",
1084                attributes);
1085                attributes.clear();
1086                
1087                if (value != null) // extra-data will be flushed later
1088
generateCharacters(value);
1089                notGenerated = false;
1090            }
1091      }
1092        
1093        /** For text nodes
1094         * if first = -1, means monovaluated
1095         */

1096        void generateTextNode(long first, long last, PathNode path)
1097        throws XMLDBCException, SQLException JavaDoc
1098        {
1099            Tuple defaultTuple = tuplePool.get(defaultMappingIndex);
1100            if (defaultTuple.isInRangeAbs(first, last , path.getPathID()))
1101                generateTextNode();
1102        }
1103        
1104        /** For text nodes
1105         * if first = -1, means monovaluated
1106         */

1107        void generateTextNode()
1108        throws RepositoryException, SQLException JavaDoc, XMLDBCException
1109        {
1110            Tuple defaultTuple = tuplePool.get(defaultMappingIndex);
1111            generateCharacters(defaultTuple.getValue(defaultColumnMapping, null, prefixProvider));
1112            defaultTuple.fetchNextRow();
1113            incChildCount(); // TEXT node
1114
}
1115        
1116        /** for element data */
1117        void generateCharacters(String JavaDoc textData) throws RepositoryException
1118        {
1119            /* interpolate character data with insertedNodes in the list and send SAX events */
1120            int lastOffset = 0;
1121            Iterator it = nodesToInsert.iterator();
1122            ExtraNode node;
1123            char[] data = null;
1124            
1125            if (textData == null)
1126            {
1127                if (nodesToInsert.size() == 0)
1128                    return;
1129                data = new char[0];
1130            }
1131            else
1132                data = textData.toCharArray();
1133            
1134            int maxGlobalOffset = charCount + data.length;
1135            while (it.hasNext())
1136            {
1137                node = (ExtraNode)it.next();
1138                if (node.offset > (lastOffset + charCount))
1139                {
1140                    ///////////////////////
1141
// SAX Characters
1142
///////////////////////
1143
try
1144                    {
1145                        contentHandler.characters(data, lastOffset,
1146                        (node.offset < maxGlobalOffset ? node.offset : maxGlobalOffset) - (lastOffset + charCount));
1147                    }
1148                    catch(SAXException JavaDoc e)
1149                    {
1150                        throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR, "SAX Exception thrown during characters() with the following message : "+e.getMessage());
1151                    }
1152                    
1153                    lastOffset = node.offset - charCount;
1154                }
1155                
1156                if ((node.position == childCount + 1) && (node.offset <= maxGlobalOffset))
1157                {
1158                    try
1159                    {
1160                        switch (node.type)
1161                        {
1162                            case NodeKind.PI:
1163                                StringTokenizer st = new StringTokenizer(node.data);
1164                                contentHandler.processingInstruction(st.nextToken(), st.nextToken(""));
1165                                break;
1166                                
1167                            case NodeKind.COMMENT :
1168                                if (lexicalHandler != null)
1169                                    lexicalHandler.comment(node.data.toCharArray(), 0, node.data.length());
1170                                break;
1171                            case START_CDATA_SECTION:
1172                                if (lexicalHandler != null)
1173                                    lexicalHandler.startCDATA();
1174                                break;
1175                            case END_CDATA_SECTION:
1176                                if (lexicalHandler != null)
1177                                    lexicalHandler.endCDATA();
1178                                break;
1179                            default :
1180                        }
1181                    }
1182                    catch(SAXException JavaDoc e)
1183                    {
1184                        String JavaDoc methodName = null;
1185                        switch (node.type)
1186                        {
1187                            case NodeKind.PI:
1188                                methodName = "processingInstruction()";
1189                                break;
1190                            case NodeKind.COMMENT :
1191                                methodName = "comment()";
1192                                break;
1193                            case START_CDATA_SECTION:
1194                                methodName = "startCDATA()";
1195                                break;
1196                            case END_CDATA_SECTION:
1197                                methodName = "endCDATA()";
1198                                break;
1199                            default :
1200                        }
1201                        throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR,
1202                        "SAX Exception thrown during " + methodName
1203                        + " with the following message : "+e.getMessage());
1204                    }
1205                    it.remove();
1206                    incChildCount(); // child count must only be incremented when the rigth place is found
1207
}
1208            }
1209            // process potential remaining character data
1210
if (lastOffset < data.length) // characters have to be saved
1211
{
1212                ///////////////////////
1213
// SAX Characters
1214
///////////////////////
1215
try
1216                {
1217                    contentHandler.characters(data, lastOffset, data.length - lastOffset);
1218                }
1219                catch(SAXException JavaDoc e)
1220                {
1221                    throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR, "SAX Exception thrown during characters() with the following message : "+e.getMessage());
1222                }
1223            }
1224            
1225            // increment element counter
1226
charCount = maxGlobalOffset;
1227        }
1228        
1229        /** for extra node without character data */
1230        void flushExtraData(boolean carriageReturn, boolean checkPosition)
1231        throws RepositoryException, SAXException JavaDoc
1232        {
1233            extraFlushed = true; // flag setting
1234

1235            Iterator it = nodesToInsert.iterator();
1236            ExtraNode node;
1237            while (it.hasNext())
1238            {
1239                node = (ExtraNode)it.next();
1240                if ( !checkPosition || (node.position == childCount + 1)) // do not check offset : trim whitespaces may carry out "out of bounds"...
1241
{
1242                    if (carriageReturn)
1243                        contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 0, 1);
1244                   switch (node.type)
1245                    {
1246                        case NodeKind.PI:
1247                            StringTokenizer st = new StringTokenizer(node.data);
1248                            try
1249                            {
1250                                contentHandler.processingInstruction(st.nextToken(), st.nextToken(""));
1251                            }
1252                            catch(SAXException JavaDoc e)
1253                            {
1254                                throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR, "SAX Exception thrown during processingInstruction() with the following message : "+e.getMessage());
1255                            }
1256                            break;
1257                            
1258                        case NodeKind.COMMENT :
1259                            if (lexicalHandler != null)
1260                            {
1261                                try
1262                                {
1263                                    lexicalHandler.comment(node.data.toCharArray(), 0, node.data.length());
1264                                }
1265                                catch(SAXException JavaDoc e)
1266                                {
1267                                    throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR, "SAX Exception thrown during comment() with the following message : "+e.getMessage());
1268                                }
1269                            }
1270                            break;
1271                        default :
1272                    }
1273                    it.remove();
1274                    incChildCount(); // child count must only be incremented when the rigth place is found
1275
}
1276            }
1277        }
1278    }
1279    
1280    /* TO IMPROVE: This implementation ensures one prefix for one namespace but is
1281     * not contextual.
1282     */

1283    protected class PrefixProvider implements ValidationContextProvider
1284    {
1285        private NamespaceContextStack nsContextStack;
1286        private int generatedPrefixCount = 1;
1287        
1288        public PrefixProvider()
1289        {
1290            nsContextStack = new NamespaceContextStack();
1291        }
1292
1293        public PrefixProvider(NamespaceContextStack nsContextStack)
1294        {
1295            this.nsContextStack = nsContextStack;
1296        }
1297
1298        /** To override for queries
1299         */

1300        public String JavaDoc getPrefix(String JavaDoc uri)
1301        {
1302            return nsContextStack.getPrefix(uri);
1303        }
1304        
1305        String JavaDoc getGeneratedPrefix(PathNode path)
1306        {
1307            String JavaDoc newPfx = null;
1308            
1309            // look in the declaration first
1310
Declaration decl = path.getDeclaration();
1311            if (decl != null)
1312                newPfx = decl.getSchema().getPrefix();
1313            
1314            // generate new prefix
1315
if ((newPfx == null) || (newPfx.length() == 0))
1316            {
1317                do
1318                {
1319                    newPfx = "ns" + generatedPrefixCount++;
1320                }
1321                while (nsContextStack.getNamespaceURI(newPfx) != null);
1322            }
1323           
1324            declarePrefix(newPfx, path.getNamespace());
1325            return newPfx;
1326        }
1327        
1328        /** @return true if the prefix is new
1329         */

1330        protected boolean declarePrefix(String JavaDoc prefix, String JavaDoc uri)
1331        {
1332            boolean newPfx = (getPrefix(uri) == null);
1333            if (newPfx)
1334                nsContextStack.declarePrefix(prefix, uri);
1335            return newPfx;
1336        }
1337        
1338        public String JavaDoc getNamespaceURI(String JavaDoc prefix)
1339        {
1340            return nsContextStack.getNamespaceURI(prefix);
1341        }
1342        
1343        public String JavaDoc getDocumentBase()
1344        {
1345            return null;
1346        }
1347        
1348        void clear()
1349        {
1350            nsContextStack = new NamespaceContextStack();
1351            generatedPrefixCount = 1;
1352        }
1353        
1354        public java.util.Map JavaDoc getNotationDeclarations()
1355        {
1356            return null;
1357        }
1358        
1359        void push()
1360        {
1361            nsContextStack.pushContext();
1362        }
1363        
1364        void pop()
1365        {
1366            nsContextStack.popContext();
1367        }
1368    }
1369}
1370
Popular Tags