KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > extractor > runtime > SynchronizedResultSet


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 package org.xquark.extractor.runtime;
24
25 import java.sql.*;
26 import java.util.ArrayList JavaDoc;
27 import java.util.List JavaDoc;
28
29 import org.xml.sax.ContentHandler JavaDoc;
30 import org.xml.sax.ErrorHandler JavaDoc;
31 import org.xml.sax.SAXException JavaDoc;
32 import org.xml.sax.ext.LexicalHandler JavaDoc;
33 import org.xml.sax.helpers.AttributesImpl JavaDoc;
34 import org.xquark.extractor.algebra.MapItem;
35 import org.xquark.extractor.algebra.Mapper;
36 import org.xquark.extractor.common.Debug;
37 import org.xquark.extractor.common.MessageLibrary;
38 import org.xquark.extractor.common.SqlWrapperException;
39 import org.xquark.extractor.metadata.ExtractorMappingInfo;
40 import org.xquark.extractor.sql.StatementInfo;
41 import org.xquark.jdbc.typing.DBMSInfo;
42 import org.xquark.schema.SchemaConstants;
43 import org.xquark.schema.SchemaException;
44 import org.xquark.schema.SimpleType;
45 import org.xquark.schema.validation.PSVInfoSetProvider;
46 import org.xquark.xml.xdbc.XMLDBCException;
47 import org.xquark.xquery.parser.Step;
48 import org.xquark.xquery.parser.XQueryException;
49 import org.xquark.xquery.xdbc.XDBCResultSetInterface;
50
51 /**
52  * Extractor implementation of the {@link org.xquark.xquery.xdbc.XDBCResultSetInterface}
53  * using a list of dependent result sets for overlapping FLWORs. This is the multiple
54  * JDBC result sets implementation of XML result set (vs the unique SOU).
55  */

56 public final class SynchronizedResultSet implements XDBCResultSetInterface {
57
58     private static final String JavaDoc RCSRevision = "$Revision: 1.5 $";
59     private static final String JavaDoc RCSName = "$Name: $";
60
61     static final Object JavaDoc NULLID = new Object JavaDoc();
62     static final AttributesImpl JavaDoc NULL_ATTRIBUTE = new AttributesImpl JavaDoc();
63
64     /* a enveloped JDBC ResultSet providing lookAhead capacity */
65     private LookAheadJdbcResultSet _lookAheadRes;
66
67     /** a mapper mapping XQuery Expressions(String) to attribute names in the JDBC ResultSet */
68     private Mapper _mapper;
69
70     private boolean _hasIdentifiers = false;
71
72     /** identifier values in current tuple. (a identifier may be composed of multiple attributes.
73      * In this case, these attribute values will be placed in a List )
74      */

75     private Object JavaDoc[] _aoThisId;
76
77     /* identifier values in next tuple. */
78     private Object JavaDoc[] _aoThisNextId;
79
80     private int _reconstructionIdCount = 0;
81
82     /** when getIdentifiers(Object[] ids) or getNextIdentifiers(Object[] ids) is called,
83      * the identifiers in this result set should be put into the arry "ids" at proper position.
84      * _aiIPosition indicate the position where a identier should be placed.
85      */

86     private int[] _aiIdPosition;
87
88     /** a list of SychronizedResultSet that depand on this SychronizedResultSet */
89     private List JavaDoc _slaveList;
90
91     /** the result set on which this one depends. When this one is root, _father = null. */
92     private SynchronizedResultSet _father;
93
94     /** indicate which slave result set is active(it will response getIdentifers(..), generate(..),... ).
95      * Rangs from -1 to _maxSlaveIndex. -1 means that this result set is active.
96      */

97     private int _curSlaveIndex = 0;
98
99     /* indicate the index of the last slave available in <code>_slaveList<code> */
100     private int _maxSlaveIndex;
101
102     /* = true this result set is synchronized with its father. */
103     private boolean _isSynchronizedWithFather = false;
104
105     /* = true when this resultset is closed */
106     private boolean _isClosed = false;
107
108     private ContentHandler JavaDoc _contenthandler = null;
109     private LexicalHandler JavaDoc _lexicalhandler = null;
110     private ErrorHandler JavaDoc _errorhandler = null;
111
112     /* a JDBC Statement used to execute SQL <code>requestList<code> */
113     private Statement _jdbcStatement = null;
114
115     /**
116      * Construct a new SynchronizedResultSet.
117      * @param requestList a list of SQL Statement.
118      * @param mapper a mapping from XQuery paths to attribute names.
119      * @param jdbcStatement a JDBC Statement used to execute SQL <code>requestList<code>.
120      * this <code>jdbcStatement<code> will be close() either when the all the result is
121      * scaned or when this SynchronizedResultSet is closed.
122      * @throws XMLDBCException if failed in executing the <code>requestList<code>.
123      */

124     public SynchronizedResultSet(List JavaDoc requestList, Mapper mapper, Statement jdbcStatement, DBMSInfo info)
125     throws XMLDBCException {
126         try {
127             init(jdbcStatement, executeRequests(requestList, jdbcStatement), mapper, info);
128         }
129         catch (SQLException ex) {
130             throw new XMLDBCException(ex.getMessage(), ex);
131         }
132
133         _jdbcStatement = jdbcStatement; // to close when result set exhausted
134
}
135
136     public SynchronizedResultSet(PreparedStatement pStmt, Mapper mapper, DBMSInfo info)
137     throws XMLDBCException {
138         try {
139             init(pStmt, pStmt.executeQuery(), mapper, info);
140         }
141         catch (SQLException ex) {
142             throw new XMLDBCException(ex.getMessage(), ex);
143         }
144     }
145
146     private void init(Statement jdbcStatement, ResultSet jdbcResultSet, Mapper mapper, DBMSInfo info)
147     throws XMLDBCException {
148         try {
149             try {
150                 _lookAheadRes = new LookAheadJdbcResultSet(jdbcResultSet, mapper, info);
151             }
152             catch (XQueryException e) {
153                 throw new XMLDBCException("Could not get next results from result set.", e);
154             }
155
156             SQLWarning warning = null;
157             warning = jdbcStatement.getWarnings();
158             if (null != warning) {
159                 throw warning;
160             }
161             warning = jdbcResultSet.getWarnings();
162             if (null != warning) {
163                 throw warning;
164             }
165         }
166         catch (SQLException ex) {
167             throw new XMLDBCException(ex.getMessage(), ex);
168         }
169
170         mapper.optimize();
171         setMapper(mapper);
172     }
173
174     /**
175      * setter methode of _aiIdPosition.
176      * @param idPosition when getIdentifiers(Object[] ids) or getNextIdentifiers(Object[] ids) is called,
177      * the identifiers in this result set should be put into the arry "ids" at proper position.
178      * idPosition indicates the position where a identier should be placed. eg. [0, 2 , 3, 0 , 0] means
179      * the first id in this result set should be the first element in <code>ids<code>, the second id should
180      * be the third element, the third id the fourth element. trailling "0" are ignored.
181      */

182     public void setIdPosition(int[] idPosition) {
183         _aiIdPosition = idPosition;
184     }
185
186     public int getReconstructionIdCount() {
187         return _reconstructionIdCount;
188     }
189
190     public void setReconstructionIdCount(int idCount) {
191         _reconstructionIdCount = idCount;
192     }
193
194     /**
195      * setter method of _mapper
196      * @param mapper
197      */

198     public void setMapper(Mapper mapper) {
199         _mapper = mapper;
200
201         List JavaDoc idMapItemList = mapper.getIdentifierList();
202         if (null != idMapItemList && !idMapItemList.isEmpty()) {
203             int idNumber = mapper.getIdentifierList().size();
204             _aoThisId = new Object JavaDoc[idNumber];
205             _aoThisNextId = new Object JavaDoc[idNumber];
206
207             _hasIdentifiers = true;
208         } else {
209             _hasIdentifiers = false;
210         }
211     }
212
213     /**
214      * setter method of _father.
215      * @param father
216      */

217     void setFather(SynchronizedResultSet father) {
218         _father = father;
219     }
220
221     /**
222      * setter methode of _slaveList.
223      * @param slaveList
224      */

225     public void setSlaveList(List JavaDoc slaveList) {
226         _slaveList = slaveList;
227
228         if (null != _slaveList) {
229             _maxSlaveIndex = _slaveList.size() - 1;
230             SynchronizedResultSet slave = null;
231             for (int i = 0; i < _maxSlaveIndex + 1; i++) {
232                 slave = (SynchronizedResultSet) _slaveList.get(i);
233                 slave.setFather(this);
234             }
235             // added to avoid having slaveList empty
236
}
237     }
238
239     /**
240      * Execute a list of SQL request assuming only the last return results and
241      * others only perform updates.
242      * @param requestList
243      * @param jdbcStatement
244      * @return a ResultSet contains data return by the last request in <code>requestList<code>.
245      * @throws SQLException
246      */

247     protected ResultSet executeRequests(List JavaDoc requestList, Statement jdbcStatement)
248     throws SQLException {
249         StatementInfo request = null;
250         int last = requestList.size() - 1;
251         for (int i = 0; i < last; i++) {
252             request = (StatementInfo) requestList.get(i);
253             jdbcStatement.executeUpdate(request.sStmt);
254         }
255         request = (StatementInfo) requestList.get(last);
256         return jdbcStatement.executeQuery(request.sStmt);
257     }
258
259     /**
260      * Releases this SynchronizedResultSet object's database and JDBC resources immediately
261      * instead of waiting for this to happen when it is automatically closed.
262      * @throws XMLDBCException if a database access error occurs
263      */

264     public void close() throws XMLDBCException {
265         if (!_isClosed) {
266             /* close slave result set */
267             if (!isLeaf()) {
268                 SynchronizedResultSet slave = null;
269                 for (int i = 0; i < _slaveList.size(); i++) {
270                     slave = (SynchronizedResultSet) _slaveList.get(i);
271                     slave.close();
272                 }
273             }
274
275             /* close this result set */
276             try {
277                 if (_jdbcStatement != null) {
278                     _jdbcStatement.close();
279                     _jdbcStatement = null;
280                 }
281                 if (_lookAheadRes != null) {
282                     _lookAheadRes.close();
283                     _lookAheadRes = null;
284                 }
285             } catch (SQLException ex) {
286                 throw new XMLDBCException(ex.getMessage(), ex);
287             }
288             _isClosed = true;
289         }
290     }
291
292     public boolean next() throws XMLDBCException {
293         boolean retVal = false;
294
295         if (isLeaf()) {
296             retVal = nextInThis();
297         } else if (isRoot()) {
298             retVal = next_internalNode();
299         } else /* internal node node */ {
300             retVal = next_internalNode();
301         }
302
303         return retVal;
304     }
305
306     /**
307      * Looks for (in this SynchronizedResultSet and this slaves)and move to next result
308      * ( a tuple whoes identifiers correspond to father identifiers when this result set
309      * is not root. if not found, stay in current tuple.
310      * @return true when found.
311      * @throws XMLDBCException
312      */

313     protected boolean next_internalNode() throws XMLDBCException {
314         //Trace.enter(this, "nextAsIntermediate()");
315
boolean retVal = false;
316
317         if (!_isSynchronizedWithFather || _curSlaveIndex == -1) {
318             retVal = nextInThis();
319             if (retVal) {
320                 _curSlaveIndex = 0;
321                 retVal = nextInSlaves();
322                 if (!retVal) {
323                     _curSlaveIndex = -1;
324                     retVal = true;
325                 }
326             }
327         } else {
328             retVal = nextInSlaves();
329             if (!retVal) {
330                 retVal = nextInThis();
331                 if (retVal) {
332                     _curSlaveIndex = 0;
333                     retVal = nextInSlaves();
334                     if (!retVal) {
335                         _curSlaveIndex = -1;
336                         retVal = true;
337                     }
338                 }
339             }
340         }
341         //Trace.exit(this, "nextAsIntermediate()");
342
return retVal;
343     }
344
345     /**
346      * Looks for (in this SynchronizedResultSet only) and move to next result
347      * ( a tuple whoes identifiers correspond to father identifiers when this
348      * result set is not root. if not found, stay in current tuple.
349      * @return true when found.
350      * @throws XMLDBCException
351      */

352     protected boolean nextInThis() throws XMLDBCException {
353         //Trace.enter(this, "nextInThis()");
354
boolean retVal = false;
355         try {
356             if (!isRoot()) {
357                 /* this resultset has a father */
358                 if (_lookAheadRes.hasNext()) {
359                     _lookAheadRes.lookAhead();
360                     feedIdentifiers(_aoThisNextId);
361                     _lookAheadRes.goBack();
362                     if (isSynchronized(_father._aoThisId, _aoThisNextId)) {
363                         try {
364                             _lookAheadRes.next();
365                         } catch (SQLException ex) {
366                             throw new XMLDBCException(MessageLibrary.getMessage("D_ACC_FAIL", ex.getMessage()), ex);
367                             /* throw XMLDBCException() */
368                         }
369                         for (int i = 0; i < _aoThisNextId.length; i++) {
370                             _aoThisId[i] = _aoThisNextId[i];
371                         }
372                         retVal = true;
373                     }
374                 }
375             } else {
376                 /* this resultset is the root. */
377                 if (_lookAheadRes.hasNext()) {
378                     try {
379                         _lookAheadRes.next();
380                     } catch (SQLException ex) {
381                         throw new XMLDBCException(MessageLibrary.getMessage("D_ACC_FAIL", ex.getMessage()), ex);
382                     }
383                     feedIdentifiers(_aoThisId);
384                     retVal = true;
385                 }
386             }
387         } catch (XQueryException e) {
388             throw new XMLDBCException("Could not get next results from result set.", e);
389         }
390
391         if (retVal) {
392             notifySlaves();
393             _isSynchronizedWithFather = true;
394         }
395
396         //Trace.exit(this, "nextInThis()");
397
return retVal;
398     }
399
400     /**
401      * Looks for (in this SynchronizedResultSet and this slaves)and move to next result
402      * ( a tuple whoes identifiers correspond to father identifiers when this result set
403      * is not root. if not found, stay in current tuple. if a result is found in a slave,
404      * point _curSlaveIndex to it.
405      * @return true when found.
406      * @throws XMLDBCException
407      */

408     protected boolean nextInSlaves() {
409         //Trace.enter(this, "nextInSlaves()");
410
boolean retVal = false;
411
412         SynchronizedResultSet curSlave = null;
413         for (int i = _curSlaveIndex; i <= _maxSlaveIndex; i++) {
414             curSlave = (SynchronizedResultSet) _slaveList.get(i);
415             try {
416                 retVal = curSlave.next();
417             } catch (XMLDBCException ex) {
418                 continue;
419             }
420             if (retVal) {
421                 _curSlaveIndex = i;
422                 retVal = true;
423                 break;
424             }
425         }
426
427         //Trace.exit(this, "nextInSlaves()");
428
return retVal;
429     }
430
431     /** Call <code>fatherIdsChanged()<code> method on all slaves.
432      */

433     protected void notifySlaves() {
434         //Trace.enter(this, "notifySlaves()");
435
if (null != _slaveList) {
436             SynchronizedResultSet slave = null;
437             for (int i = 0; i < _slaveList.size(); i++) {
438                 slave = (SynchronizedResultSet) _slaveList.get(i);
439                 slave.fatherIdsChanged();
440             }
441         }
442         //Trace.exit(this, "notifySlaves()");
443

444     }
445
446     /**
447      * Set _isSynchronizedWithFather to <code>false<code>;
448      * This method should be called by the father whenenver his id values change.
449      */

450     protected void fatherIdsChanged() {
451         _isSynchronizedWithFather = false;
452     }
453
454     public boolean hasNext() throws XMLDBCException {
455         //Trace.enter(this, "hasNext()");
456
if (_isClosed)
457             throw new XMLDBCException(MessageLibrary.getMessage("RS_CLOSED"));
458         boolean retVal = false;
459
460         retVal = _lookAheadRes.hasNext();
461         /* we do not care about whether the next tuple is the one to be returned later */
462
463         if (!retVal) {
464             SynchronizedResultSet curSlave = null;
465             if (_curSlaveIndex != -1 && !isLeaf()) {
466                 for (int i = _curSlaveIndex; i <= _maxSlaveIndex; i++) {
467                     curSlave = (SynchronizedResultSet) _slaveList.get(i);
468                     retVal = curSlave.hasNext();
469                     /* again, we do not care about whether the next tuple is the one to be returned later */
470                     if (retVal) {
471                         break;
472                     }
473                 }
474             }
475         }
476
477         //Trace.exit(this, "hasNext()", retVal ? "true" : "false");
478
return retVal;
479     }
480
481     public void getIdentifiers(Object JavaDoc[] ids) throws XMLDBCException {
482         //Trace.enter(this, "getIdentifiers(Object[] ids)");
483
if (_isClosed)
484             throw new XMLDBCException(MessageLibrary.getMessage("RS_CLOSED"));
485         if (!_hasIdentifiers)
486             throw new XMLDBCException(MessageLibrary.getMessage("RS_NO_ID"), null);
487
488         if (!isLeaf() && _curSlaveIndex >= 0) {
489             /* return ids in current Slave */
490             SynchronizedResultSet curSlave = (SynchronizedResultSet) _slaveList.get(_curSlaveIndex);
491             curSlave.getIdentifiers(ids);
492         } else {
493             fillIdsWithCache(ids, _aoThisId);
494         }
495
496         StringBuffer JavaDoc idsBuf = new StringBuffer JavaDoc();
497         printArray(idsBuf, ids);
498         //Trace.message(this, "getIdentifiers(Object[] ids) ids:", idsBuf.toString());
499
//Trace.exit(this, "getIdentifiers(Object[] ids)");
500
}
501
502     private void printArray(StringBuffer JavaDoc buffer, Object JavaDoc[] array) {
503         buffer.append('[');
504         for (int i = 0; i < array.length; i++) {
505             Object JavaDoc item = array[i];
506             if (item instanceof Object JavaDoc[]) {
507                 printArray(buffer, array);
508             }
509             if (null != item) {
510                 buffer.append(item.toString());
511             }
512
513             buffer.append(",\t");
514         }
515         buffer.append(']');
516     }
517
518     /**
519      * Get identifiers values from <code>_lookAheadRes<code>, and put them in to <code>ids<code>.
520      * @param ids
521      * @throws XMLDBCException if no identifiers are provided in this <code>SynchronizedResultSet<code>.
522      */

523     protected void feedIdentifiers(Object JavaDoc[] ids) throws XMLDBCException {
524         //Trace.enter(this, "feedIdentifiers(Object[] ids)");
525

526         List JavaDoc lmiIdItemList = _mapper.getIdentifierList();
527         Object JavaDoc id = null;
528         if (null != lmiIdItemList) {
529             MapItem idItem = null;
530             for (int i = 0; i < lmiIdItemList.size(); i++) {
531                 idItem = (MapItem) lmiIdItemList.get(i);
532                 id = getIdentifiers(idItem);
533                 ids[i] = id;
534             }
535         }
536
537         //Trace.exit(this, "feedIdentifiers(Object[] ids)");
538
}
539
540     /**
541      * get identifier value at cursor position(<code>BUFFER<code> or <code>RESULTSET<code>) in <code>_lookAheadRes<code>.
542      * @param idItem a MapItem representing a identifier(might).
543      * @return a Object contains identifier value.
544      * @throws XMLDBCException database access failed.
545      */

546     protected Object JavaDoc getIdentifiers(MapItem idItem) throws XMLDBCException {
547         //Trace.enter(this, "getIdentifiers(MapItem idItem)");
548
Object JavaDoc retVal = null;
549
550         try {
551             if (idItem.isLeafPath()) {
552                 retVal = _lookAheadRes.getString(idItem.getItemName());
553                 if (null == retVal) {
554                     retVal = NULLID;
555                 }
556             } else {
557                 List JavaDoc idAttrs = new ArrayList JavaDoc();
558                 List JavaDoc children = idItem.getChildItemList();
559                 for (int j = 0; j < children.size(); j++) {
560                     MapItem child = (MapItem) children.get(j);
561                     String JavaDoc attrValue = _lookAheadRes.getString(child.getItemName());
562                     idAttrs.add(attrValue);
563                 }
564                 retVal = idAttrs;
565             }
566         } catch (SQLException ex) {
567             throw new XMLDBCException(MessageLibrary.getMessage("D_ACC_FAIL", ex.getMessage()), ex);
568         }
569         //Trace.exit(this, "getIdentifiers(MapItem idItem)");
570
return retVal;
571     }
572
573     /**
574      * fill the array ids with next (global, logicaly)identifiers in this result set
575      * or slave result set at proper positions.
576      * @param ids
577      * @throws XMLDBCException
578      * this function should be called only when this result set is root.
579      */

580     public void getNextIdentifiers(Object JavaDoc[] ids) throws XMLDBCException {
581         //Trace.enter(this, "getNextIdentifiers(Object[] ids)");
582
if (_isClosed)
583             throw new XMLDBCException(MessageLibrary.getMessage("RS_CLOSED"));
584         if (!_hasIdentifiers)
585             throw new XMLDBCException(MessageLibrary.getMessage("RS_NO_ID"), null);
586
587         boolean retVal = false;
588         if (!_isSynchronizedWithFather) {
589             /* the "cursor" is at before-first*/
590             if (_lookAheadRes.lookAhead()) {
591                 feedIdentifiers(_aoThisNextId);
592                 _lookAheadRes.goBack();
593                 if (!isLeaf()) {
594                     retVal = getNextIdentifiersInSlaves(_aoThisNextId, ids, 0);
595                     if (!retVal) {
596                         fillIdsWithCache(ids, _aoThisNextId);
597                         retVal = true;
598                     }
599                 } else {
600                     fillIdsWithCache(ids, _aoThisNextId);
601                 }
602             } else {
603                 /* this result set is empty*/
604                 throw new XMLDBCException("getNextIdentifiers(Object[] ids) while there isn't next result ", null);
605             }
606         } else {
607             if (!isLeaf()) {
608                 /* retVal = false; */
609                 retVal = getNextIdentifiersInSlaves(_aoThisId, ids, _curSlaveIndex);
610                 if (!retVal) {
611                     if (_lookAheadRes.lookAhead()) {
612                         feedIdentifiers(_aoThisNextId);
613                         _lookAheadRes.goBack();
614                         retVal = getNextIdentifiersInSlaves(_aoThisNextId, ids, 0);
615                         if (!retVal) {
616                             fillIdsWithCache(ids, _aoThisNextId);
617                             retVal = true;
618                         }
619                     } else {
620                         /* this result set has no more result empty*/
621                         throw new XMLDBCException("getNextIdentifiers(Object[] ids) called, while there isn't next result ", null);
622                     }
623                 }
624             } else {
625                 if (_lookAheadRes.lookAhead()) {
626                     feedIdentifiers(_aoThisNextId);
627                     fillIdsWithCache(ids, _aoThisNextId);
628                     _lookAheadRes.goBack();
629                 } else {
630                     /* this result set has no more result empty*/
631                     throw new XMLDBCException("getNextIdentifiers(Object[] ids) called, while there isn't next result ", null);
632                 }
633             }
634         }
635         StringBuffer JavaDoc idsBuf = new StringBuffer JavaDoc();
636         printArray(idsBuf, ids);
637         //Trace.message(this, "getIdentifiers(Object[] ids) ids:", idsBuf.toString());
638
//Trace.exit(this, "getNextIdentifiers(Object[] ids)", ids);
639
}
640
641     /**
642      * Looks for next identifiers in this SynchronizedResultSet and its slaves(when there are).
643      * @param fatherIds identifiers whith whom the return values should be synchronized.
644      * @param ids a array where the identifiers found should be put.
645      * @param startIndex begin index of slave resultset from which.
646      * @return true if found.
647      * @throws XMLDBCException
648      */

649     protected boolean getNextIdentifiersOf(Object JavaDoc[] fatherIds, Object JavaDoc[] ids) throws XMLDBCException {
650         //Trace.enter(this, "protected boolean getNextIdentifiersOf(Object[] fatherIds, Object[] ids)");
651
boolean retVal = false;
652
653         if (isLeaf()) {
654             retVal = getNextIdentifiersOf_leaf(fatherIds, ids);
655         } else {
656             retVal = getNextIdentifiersOf_internalNode(fatherIds, ids);
657         }
658
659         //Trace.exit(this, "protected boolean getNextIdentifiersOf(Object[] fatherIds, Object[] ids)");
660
return retVal;
661     }
662
663     /**
664      * Looks for next identifiers in this SynchronizedResultSet and its slaves. This function
665      * should be called only when this result set is not root node.
666      * @param fatherIds identifiers whith whom the return values should be synchronized.
667      * @param ids a array where the identifiers found should be put.
668      * @param startIndex begin index of slave resultset from which.
669      * @return true if found.
670      * @throws XMLDBCException
671      */

672     protected boolean getNextIdentifiersOf_internalNode(Object JavaDoc[] fatherIds, Object JavaDoc[] ids) throws XMLDBCException {
673         //Trace.enter(this, "getNextIdentifiersOf_internalNode(Object[] fatherIds, Object[] ids)");
674

675         boolean retVal = false;
676         if (!_isSynchronizedWithFather) {
677             if (_lookAheadRes.lookAhead()) {
678                 feedIdentifiers(_aoThisNextId);
679                 _lookAheadRes.goBack();
680                 if (isSynchronized(fatherIds, _aoThisNextId)) {
681                     retVal = getNextIdentifiersInSlaves(_aoThisNextId, ids, 0);
682                     if (!retVal) {
683                         fillIdsWithCache(ids, _aoThisNextId);
684                         retVal = true;
685                     }
686                 }
687
688             }
689         } else {
690             /* this result set is already synchronized with his father */
691             retVal = getNextIdentifiersInSlaves(_aoThisId, ids, _curSlaveIndex);
692             if (!retVal) {
693                 if (_lookAheadRes.lookAhead()) {
694                     feedIdentifiers(_aoThisNextId); /*/** @todo */
695                     _lookAheadRes.goBack();
696                     if (isSynchronized(fatherIds, _aoThisNextId)) {
697                         retVal = getNextIdentifiersInSlaves(_aoThisNextId, ids, 0);
698                         if (!retVal) {
699                             fillIdsWithCache(ids, _aoThisNextId);
700                             retVal = true;
701                         }
702                     }
703                 }
704             }
705         }
706
707         //Trace.exit(this, "getNextIdentifiersOf_internalNode(Object[] fatherIds, Object[] ids)");
708
return retVal;
709     }
710
711     protected void fillIdsWithCache(Object JavaDoc[] ids, Object JavaDoc[] cache) {
712         /* fill ids with _thisNextId */
713         for (int i = 0; i < ids.length; i++) {
714             ids[i] = null;
715         }
716
717         for (int i = 0; i < cache.length; i++) {
718             ids[_aiIdPosition == null ? i : _aiIdPosition[i]] = cache[i];
719         }
720
721     }
722
723     /**
724      * Looks for next identifiers in slave result set.
725      * @param fatherIds identifiers whith whom the return values should be synchronized.
726      * @param ids a array where the identifiers found should be put.
727      * @param startIndex begin index of slave resultset from which.
728      * @return true if found.
729      * @throws XMLDBCException
730      */

731     protected boolean getNextIdentifiersInSlaves(Object JavaDoc[] fatherIds, Object JavaDoc[] ids, int startIndex) throws XMLDBCException {
732         //Trace.enter(this, "getNextIdentifiersInSlaves(Object[] ids)");
733
boolean retVal = false;
734
735         SynchronizedResultSet curSlave = null;
736         if (startIndex != -1) {
737             for (int i = startIndex; i <= _maxSlaveIndex; i++) {
738                 curSlave = (SynchronizedResultSet) _slaveList.get(i);
739                 retVal = curSlave.getNextIdentifiersOf(fatherIds, ids);
740                 if (retVal) {
741                     break;
742                 }
743             }
744         }
745
746         //Trace.exit(this, "getNextIdentifiersInSlaves(Object[] ids)");
747
return retVal;
748     }
749
750     /**
751      * Looks for next identifiers in this SynchronizedResultSet only.
752      * @param fatherIds identifiers whith whom the return values should be synchronized.
753      * @param ids a array where the identifiers found should be put.
754      * @param startIndex begin index of slave resultset from which.
755      * @return true if found.
756      * @throws XMLDBCException
757      */

758     protected boolean getNextIdentifiersOf_leaf(Object JavaDoc[] fatherIds, Object JavaDoc[] ids) throws XMLDBCException {
759         //Trace.enter(this, "getNextIdentifiersOf_leaf(Object[] fatherIds, Object[] ids)");
760

761         boolean retVal = false;
762         if (_lookAheadRes.lookAhead()) {
763             feedIdentifiers(_aoThisNextId);
764             _lookAheadRes.goBack();
765             if (isSynchronized(fatherIds, _aoThisNextId)) {
766                 fillIdsWithCache(ids, _aoThisNextId);
767                 retVal = true;
768             }
769         }
770
771         //Trace.exit(this, "getNextIdentifiersOf_leaf(Object[] fatherIds, Object[] ids)");
772
return retVal;
773     }
774
775     /**
776      * Implements <code>generate(String path,int nodeAccessor,String loopID)<code>.
777      * @param path
778      * @param nodeAccessor
779      * @param loopID
780      * @throws XMLDBCException
781      */

782     public void generate(String JavaDoc path, int nodeAccessor, String JavaDoc loopID) throws XMLDBCException {
783         generate(path, nodeAccessor);
784     }
785
786     public void generate(String JavaDoc path, int nodeAccessor) throws XMLDBCException {
787         generate(path, nodeAccessor, (PSVInfoSetProvider) null);
788     }
789
790     public void generate(String JavaDoc path, int nodeAccessor, String JavaDoc loopID, PSVInfoSetProvider psvisp) throws XMLDBCException {
791         generate(path, nodeAccessor, psvisp);
792     }
793
794     public void generate(String JavaDoc path, int nodeAccessor, PSVInfoSetProvider psvisp) throws XMLDBCException {
795         /* argument <code> String loopID <code> is always ignored */
796         //Trace.enter(this, "generate(String path,int nodeAccessor,String loopID)", path);
797
if (_isClosed)
798             throw new XMLDBCException(MessageLibrary.getMessage("RS_CLOSED"));
799         if (_contenthandler != null) {
800             if (_curSlaveIndex != -1 && !isLeaf()) {
801                 /* a slave is active */
802                 SynchronizedResultSet curSlave = (SynchronizedResultSet) _slaveList.get(_curSlaveIndex);
803                 curSlave.generate(path, nodeAccessor);
804             } else {
805                 /* this result set is active */
806                 MapItem mapItem = _mapper.map(path);
807                 if (mapItem == null) {
808                     int toto = 0;
809                 }
810                 Debug.assertTrue(null != mapItem, "null!=mapItem");
811                 switch (nodeAccessor) {
812                     case 0 :
813                         generate(mapItem, psvisp);
814                         break;
815                     case Step.CHILD_TEXT :
816                     //case XDBCResultSetInterface.NODE_ACCESSOR_TEXT :
817
/* mapItem should represent a element of simple type */
818                         String JavaDoc value = fetch(mapItem, psvisp);
819                         if (null != value) {
820                             try {
821                                 if (psvisp != null) {
822                                     ExtractorMappingInfo emi = mapItem.getMappingInfo();
823                                     SimpleType st = emi.getXMLType();
824                                     psvisp.setActualValue(-1, st.getPrimitive().convert(value, false));
825                                     psvisp.setNormalizedValue(-1, value);
826                                 }
827                                 _contenthandler.characters(value.toCharArray(), 0, value.length());
828                             } catch (SchemaException ex) {
829                                 throw new XMLDBCException(ex.getMessage(), ex);
830                             } catch (SAXException JavaDoc ex) {
831                                 throw new XMLDBCException(ex.getMessage(), ex);
832                             }
833                         }
834                         break;
835                     case Step.CHILD_NODE :
836                     //case XDBCResultSetInterface.NODE_ACCESSOR_NODE :
837
if (mapItem.isLeafPath()) {
838                             generate(mapItem, psvisp);
839                         } else {
840                             List JavaDoc childItemList = mapItem.getChildItemList();
841                             for (int i = 0; i < childItemList.size(); i++) {
842                                 mapItem = (MapItem) childItemList.get(i);
843                                 generate(mapItem, psvisp);
844                             }
845                         }
846                         break;
847                     default :
848                         throw new XMLDBCException("Internal error : error argument in function call");
849                 }
850             }
851         }
852         //Trace.exit(this, "generate(String path,int nodeAccessor,String loopID)", path);
853
}
854
855     /**
856      * Generates XML data for given <code>MapItem<code>.
857      * @param mapItem
858      * @throws XMLDBCException
859      */

860     private final static String JavaDoc STAR = "*";
861     protected void generate(MapItem mapItem, PSVInfoSetProvider psvisp) throws XMLDBCException {
862         //Trace.enter(this, "generate(MapItem mapItem)");
863
try {
864             String JavaDoc tag = mapItem.getElementName();
865             String JavaDoc namespace = mapItem.getNamespace();
866             // add LARS
867
if (namespace != null && namespace.equals(STAR))
868                 namespace = null;
869             if (mapItem.isLeafPath()) {
870                 /* mapItem represent an element of simple type */
871                 String JavaDoc value = _lookAheadRes.getString(mapItem.getItemName());
872                 if (value != null) {
873                     if (null != tag) {
874                         if (psvisp != null) {
875                             psvisp.pushElementInfoset((namespace == null) ? "" : namespace, tag);
876                             // TODO retrieve the element declaration
877
psvisp.initElementValidationInfo(null, mapItem.getMappingInfo().getXMLType(), false, SchemaConstants.LAX);
878                         }
879                         _contenthandler.startElement((namespace == null) ? "" : namespace, tag, "", NULL_ATTRIBUTE);
880                     }
881                     if (psvisp != null) {
882                         ExtractorMappingInfo emi = mapItem.getMappingInfo();
883                         SimpleType st = emi.getXMLType();
884                         // TODO get object directly from resulset
885
psvisp.setActualValue(-1, st.getPrimitive().convert(value, false));
886                         psvisp.setNormalizedValue(-1, value);
887                     }
888                     _contenthandler.characters(value.toCharArray(), 0, value.length());
889                     if (null != tag) {
890                         _contenthandler.endElement(namespace, tag, "");
891                         if (psvisp != null) {
892                             psvisp.popElementInfoset();
893                         }
894                     }
895                 }
896             } else {
897                 /* mapItem represent an element of complex type */
898                 if (psvisp != null) {
899                     psvisp.pushElementInfoset((namespace == null) ? "" : namespace, tag);
900                     // TODO retrieve the element declaration
901
if (mapItem.getMappingInfo() != null)
902                         psvisp.initElementValidationInfo(null, mapItem.getMappingInfo().getXMLType(), false, SchemaConstants.LAX);
903                 }
904                 _contenthandler.startElement((namespace == null) ? "" : namespace, tag, "", NULL_ATTRIBUTE);
905                 List JavaDoc childItemList = mapItem.getChildItemList();
906                 for (int i = 0; i < childItemList.size(); i++) {
907                     generate((MapItem) childItemList.get(i), psvisp);
908                 }
909                 _contenthandler.endElement(namespace, tag, "");
910                 if (psvisp != null) {
911                     psvisp.popElementInfoset();
912                 }
913             }
914         } catch (SQLException ex) {
915             throw new XMLDBCException(ex.getMessage(), ex);
916         } catch (SchemaException ex) {
917             throw new XMLDBCException(ex.getMessage(), ex);
918         } catch (SAXException JavaDoc ex) {
919             throw new XMLDBCException(ex.getMessage(), ex);
920         }
921         //Trace.exit(this, "localGenerate(String path)");
922
}
923
924     protected boolean willGenerateOnlyCharacters(MapItem mapItem) throws XMLDBCException {
925         try {
926             return mapItem.isLeafPath() && _lookAheadRes.getString(mapItem.getItemName()) != null && mapItem.getElementName() == null;
927         } catch (SQLException ex) {
928             throw new XMLDBCException(ex.getMessage(), ex);
929         }
930     }
931
932     /**
933      * Implements <code>fetch(String path, int nodeAccessor, String loopID)<code> method.
934      * @param path
935      * @param nodeAccessor
936      * @param loopID
937      * @return
938      * @throws XMLDBCException
939      */

940     public String JavaDoc fetch(String JavaDoc path, int nodeAccessor, String JavaDoc loopID) throws XMLDBCException {
941         return fetch(path, nodeAccessor);
942     }
943     public String JavaDoc fetch(String JavaDoc path, int nodeAccessor) throws XMLDBCException {
944         return fetch(path, nodeAccessor, (PSVInfoSetProvider) null);
945     }
946
947     public String JavaDoc fetch(String JavaDoc path, int nodeAccessor, String JavaDoc loopID, PSVInfoSetProvider psvisp) throws XMLDBCException {
948         return fetch(path, nodeAccessor, psvisp);
949     }
950
951     public String JavaDoc fetch(String JavaDoc path, int nodeAccessor, PSVInfoSetProvider psvisp) throws XMLDBCException {
952         //Trace.enter(this, "fetch(String path, int nodeAccessor, String loopID)", path);
953
if (_isClosed)
954             throw new XMLDBCException(MessageLibrary.getMessage("RS_CLOSED"));
955         String JavaDoc retVal = null;
956
957         if (_curSlaveIndex != -1 && !isLeaf()) {
958             /* a slave is active */
959
960             SynchronizedResultSet curSlave = (SynchronizedResultSet) _slaveList.get(_curSlaveIndex);
961             retVal = curSlave.fetch(path, nodeAccessor, psvisp);
962         } else {
963             /* this result set is active */
964             MapItem mapItem = _mapper.map(path);
965             if (mapItem != null) {
966                 retVal = fetch(mapItem, psvisp);
967             } else {
968                 throw new XMLDBCException("(fetch) This path \"" + path + "\" can not be found in the result set.", null);
969             }
970         }
971         //Trace.exit(this, "fetch(String path, int nodeAccessor, String loopID)", path);
972
return retVal;
973     }
974
975     /**
976      * Get the value(no tag, no attribute) of a path represented by <code>mapItem<code>.
977      * @param mapItem
978      * @return
979      * @throws XMLDBCException
980      */

981     protected String JavaDoc fetch(MapItem mapItem, PSVInfoSetProvider psvisp) throws XMLDBCException {
982         //Trace.enter(this, "fetch(MapItem mapItem)");
983
String JavaDoc retVal = null;
984         try {
985             retVal = _lookAheadRes.getString(mapItem.getItemName());
986             // if (psvisp != null) {
987
// ExtractorMappingInfo emi = mapItem.getMappingInfo();
988
// SimpleType st = emi.getXMLType();
989
// ((ElementPSVInfosetImpl) psvisp.getCurrentInfoset()).setType(st);
990
// psvisp.setMemberType(-1,st);
991
// psvisp.setActualValue(-1,st.getPrimitive().convert(retVal,false));
992
// psvisp.setNormalizedValue(-1,retVal);
993
// }
994
}
995         // catch (SchemaException se) {
996
// throw new XMLDBCException(MessageLibrary.getMessage("D_ACC_FAIL"), se);
997
// }
998
catch (SQLException ex) {
999             throw new XMLDBCException(MessageLibrary.getMessage("D_ACC_FAIL"), ex);
1000        }
1001
1002        //Trace.exit(this, "fetch(MapItem mapItem)");
1003
return retVal;
1004    }
1005
1006    /**
1007     * Return turn if <code>thisId<code> is synchronized with <code>fatherId<code>.
1008     * @param fatherId
1009     * @param thisId
1010     * @return turn if <code>thisId<code> is synchronized with <code>fatherId<code>.
1011     */

1012    protected boolean isSynchronized(Object JavaDoc[] fatherId, Object JavaDoc[] thisId) {
1013        //Trace.enter(this, "isSynchronized(Object[] fatherId, Object[] thisId)");
1014
boolean retVal = true;
1015
1016        if (null != fatherId && null != thisId) {
1017            for (int i = 0; i < fatherId.length; i++) {
1018                retVal = fatherId[i].equals(thisId[i]);
1019                if (!retVal) {
1020                    break;
1021                }
1022            }
1023        } else {
1024            throw new SqlWrapperException(MessageLibrary.getMessage("IE_INV_ARG", "isSynchronized(Object[] fatherId, Object[] thisId)"), null);
1025        }
1026
1027        //Trace.exit(this, "isSynchronized(Object[] fatherId, Object[] thisId)");
1028
return retVal;
1029    }
1030
1031    public boolean isRoot() {
1032        return null == _father;
1033    }
1034
1035    public boolean isLeaf() {
1036        return null == _slaveList || _slaveList.isEmpty();
1037    }
1038
1039    public void setContentHandler(ContentHandler JavaDoc handler) {
1040        if (handler == null)
1041            throw new NullPointerException JavaDoc("ContentHandler can not be null.");
1042        this._contenthandler = handler;
1043
1044        if (!isLeaf()) {
1045            SynchronizedResultSet slave = null;
1046            for (int i = 0; i < _slaveList.size(); i++) {
1047                slave = (SynchronizedResultSet) _slaveList.get(i);
1048                slave.setContentHandler(_contenthandler);
1049            }
1050        }
1051    }
1052
1053    public void setLexicalHandler(LexicalHandler JavaDoc handler) {
1054        if (handler == null)
1055            throw new NullPointerException JavaDoc("LexicalHandler can not be null.");
1056        this._lexicalhandler = handler;
1057
1058        if (!isLeaf()) {
1059            SynchronizedResultSet slave = null;
1060            for (int i = 0; i < _slaveList.size(); i++) {
1061                slave = (SynchronizedResultSet) _slaveList.get(i);
1062                slave.setLexicalHandler(_lexicalhandler);
1063            }
1064        }
1065    }
1066
1067    public void setErrorHandler(ErrorHandler JavaDoc handler) {
1068        if (handler == null)
1069            throw new NullPointerException JavaDoc("ErrorHandler can not be null.");
1070        this._errorhandler = handler;
1071
1072        if (!isLeaf()) {
1073            SynchronizedResultSet slave = null;
1074            for (int i = 0; i < _slaveList.size(); i++) {
1075                slave = (SynchronizedResultSet) _slaveList.get(i);
1076                slave.setErrorHandler(_errorhandler);
1077            }
1078        }
1079    }
1080}
1081
Popular Tags