KickJava   Java API By Example, From Geeks To Geeks.

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


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.mapper.storage;
24
25 import java.io.StringWriter JavaDoc;
26 import java.sql.PreparedStatement JavaDoc;
27 import java.sql.ResultSet JavaDoc;
28 import java.sql.SQLException JavaDoc;
29 import java.util.*;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.xml.sax.Locator JavaDoc;
34 import org.xquark.mapping.Generator;
35 import org.xquark.mapping.StorageContext;
36 import org.xquark.mapper.RepositoryException;
37 import org.xquark.mapper.StorageException;
38 import org.xquark.mapper.dbms.AbstractConnection;
39 import org.xquark.mapper.dbms.JDBCBatcher;
40 import org.xquark.mapper.mapping.*;
41 import org.xquark.mapper.metadata.CollectionMappingInfo;
42 import org.xquark.mapper.metadata.Node;
43 import org.xquark.mapper.metadata.RepositoryConstants;
44 import org.xquark.mapper.util.*;
45 import org.xquark.mapper.util.Stack;
46 import org.xquark.xml.xdbc.XMLDBCException;
47 import org.xquark.xml.xdbc.XMLErrorHandler;
48
49 /** Bufferization class performing storage of XML model to database managing
50  * relational referential integrity issues.
51  *
52  * @see org.xml.sax.ContentHandler
53  */

54 public class StorageBuffer implements RepositoryConstants
55 {
56     private static final String JavaDoc RCSRevision = "$Revision: 1.6 $";
57     private static final String JavaDoc RCSName = "$Name: $";
58
59     private static Log log = LogFactory.getLog(StorageBuffer.class);
60     
61     ////////////////////////////////////////////////////////////////////
62
// DATA
63
////////////////////////////////////////////////////////////////////
64
/* Array for storing one tuple for every relational table
65      * index is managed by the repository mapping
66      */

67     TupleFactory[] tupleFactories = null;
68     
69     /* Stack containing ElementInfo to memorize that an element is mapped
70      * and maintain info to maintains the repository context.
71      * This allows to know if the text buffer must be emptied by the
72      * endElement event or by the endMapping that needs buffer content.
73      */

74     Stack elementMappingStatus = null;
75     
76     // StorageContext data (for mapping generators)
77
Node contextLink = null; // link used to maintain the repository context
78
AbstractConnection connection;
79     
80     JDBCBatcher batcher;
81     
82     private XMLErrorHandler errorHandler;
83
84     private LinkedList waitingNodes = null; // BufferNode list waiting to be stored
85
// OPTIMIZATION : LinkedList ?
86
private ArrayList bufferPool = null; // BufferNode list waiting to be recycled
87
private ArrayList modelPool = null; // ModelNode list waiting to be recycled
88

89     private MappingSet mappings;
90     private String JavaDoc collectionName;
91     private StorageContext context;
92     private boolean overrideEmptyString;
93     //
94
// XMLCollection (database) related data
95
//
96

97     //
98
// Options
99
//
100

101     /** Creates new StorageBuffer */
102     public StorageBuffer(MappingSet mappings, String JavaDoc collectionName, AbstractConnection connection,
103             JDBCBatcher batcher, StorageContext context, boolean overrideEmptyString)
104     throws RepositoryException
105     {
106         this.mappings = mappings;
107         this.collectionName = collectionName;
108         this.overrideEmptyString = overrideEmptyString;
109         waitingNodes = new LinkedList();
110         bufferPool = new ArrayList();
111         this.context = context;
112         this.batcher = batcher;
113         tupleFactories = new TupleFactory[mappings.getMappingStatementsCount()];
114         // TODO: Bug. When tables have FK but no ref are declared in mapping a useless
115
// order is enforced. More generally, if no dependency exist, an order still
116
// exist (blocking tuples...)
117
// 2 things to do:
118
// 1. After dependencies declared in mapping, a dependency tree could be build
119
// basing on DBDMS metadata verifying there is no conflict between the 2.
120
// 2. Building list of lists dependency structures instead of simple lists (like
121
// in JDBC batcher)
122
try {
123             initBatcher(connection);
124         }
125         catch (SQLException JavaDoc e) {
126             throw new RepositoryException(RepositoryException.DB_ERROR,
127             "JDBC error while creating JDBC2 batch handler", e);
128         }
129         
130         this.elementMappingStatus = new Stack();
131         this.connection = connection;
132     }
133     
134     public void setErrorHandler(XMLErrorHandler handler)
135     {
136         errorHandler = handler;
137     }
138     
139     public XMLErrorHandler getXMLErrorHandler()
140     {
141         return errorHandler;
142     }
143     
144     ////////////////////////////////////////////////////////////////////
145
// Tuple buffering general methods.
146
////////////////////////////////////////////////////////////////////
147

148     void reset() throws RepositoryException, SQLException JavaDoc
149     {
150         for (int i = 0; i < tupleFactories.length; i++)
151         {
152             tupleFactories[i].clear();
153         }
154         waitingNodes.clear();
155         bufferPool.clear();
156     }
157     
158     public void close() throws RepositoryException, SQLException JavaDoc
159     {
160         batcher = null;
161         contextLink = null;
162         connection = null;
163         for (int i = 0; i < tupleFactories.length; i++)
164         {
165             tupleFactories[i].close();
166         }
167         tupleFactories = null;
168     }
169
170     public TupleFactory getTupleFactory(int tmIndex)
171     {
172         return tupleFactories[tmIndex];
173     }
174     
175     public AbstractConnection getConnection()
176     {
177         return connection;
178     }
179
180     public void flush() throws SQLException JavaDoc, XMLDBCException
181     {
182         BufferNode wNode;
183         Iterator it = waitingNodes.iterator();
184         while (it.hasNext())
185         {
186             wNode = (BufferNode)it.next();
187             
188             if (wNode.isReady())
189                 wNode.save();
190             if (wNode.isDiscardable()) // for post-nodes that could have been saved by dependance
191
{
192                 recycle(wNode);
193                 it.remove();
194             }
195         }
196     }
197     
198     private void recycle(BufferNode recycled)
199     {
200         bufferPool.add(recycled);
201         recycled.clear();
202         // OPTIMIZATION : limit the number of recycled nodes
203
}
204     
205     public BufferNode bufferizeNode(Collection tableMappings, Locator JavaDoc locator)
206     throws RepositoryException
207     {
208         BufferNode newNode;
209         if (bufferPool.size() > 0)
210         {
211             newNode = (BufferNode)bufferPool.remove(bufferPool.size()-1);
212             newNode.addTuples(tableMappings, locator);
213             newNode.setLocation(locator);
214         }
215         else
216             newNode = new BufferNode(tableMappings, locator);
217         
218         waitingNodes.add(newNode);
219         return newNode;
220     }
221     
222     public BufferNode bufferizeDefaultNode(CollectionMappingInfo mappingInfo, Locator JavaDoc locator)
223     throws RepositoryException
224     {
225         // substitute the current default mapping view
226
TableMapping tm = mappingInfo.getTableMapping();
227         tupleFactories[tm.getTableIndex()].setMapping(tm);
228         return bufferizeNode(Collections.singletonList(tm), locator);
229     }
230     
231     protected void initBatcher(AbstractConnection connection)
232     throws RepositoryException, SQLException JavaDoc
233     {
234         // Instantiate tuple factories & Fill batcher with statements in the right order
235
int stmtIndex = -1;
236         TupleFactory factory;
237         MappingInfo mappingStmt;
238         MappingSetIterator it = mappings.getSortedTableMappingSetIterator(false);
239         while (it.hasNext())
240         {
241             mappingStmt = it.next();
242             if (it.isTableFirstOccurence() || !mappingStmt.isShareable())
243             {
244                 factory =
245                     tupleFactories[mappingStmt
246                         .getTableMapping()
247                         .getTableIndex()] =
248                         new TupleFactory(mappingStmt, connection);
249                 if (factory.getOIDStmt() != null)
250                     batcher.addStatement(
251                         factory.getOIDStmt(),
252                         mappingStmt.getOIDTableName(),
253                         RepositoryProperties.getIntProperty(
254                             CONF_TREE_BATCHSIZE));
255                 if (factory.getInsertStmt() != null)
256                     stmtIndex =
257                         batcher.addStatement(
258                             stmtIndex,
259                             factory.getInsertStmt(),
260                             factory.getMapping().getTableName(),
261                             factory.getMapping().getBatchSize());
262                 // TO REFINE
263
if (factory.getUpdateStmt() != null)
264                     batcher.addStatement(
265                         stmtIndex,
266                         factory.getUpdateStmt(),
267                         factory.getMapping().getTableName(),
268                         factory.getMapping().getBatchSize());
269                 // TO REFINE
270
}
271             else // share statement & tuple factory
272
tupleFactories[mappingStmt.getTableMapping().getTableIndex()] =
273                     tupleFactories[it.getFirstOccurenceTableIndex()];
274         }
275     }
276     
277     /*******************************************************************
278     ** INNER CLASSES **
279     *******************************************************************/

280     
281     ////////////////////////////////////////////////////////////////////
282
// BUFFER NODE
283
////////////////////////////////////////////////////////////////////
284
/**
285      * Elementary data structure used to store links & values waiting to be stored
286      */

287     public class BufferNode
288     {
289         private static final String JavaDoc RCSRevision = "$Revision: 1.6 $";
290         private static final String JavaDoc RCSName = "$Name: $";
291         ArrayList tuples = null; // for nodes corresponding to table mappings
292
boolean saved = false;
293         int line = -1;
294         int column = -1;
295         
296         BufferNode() {}
297         BufferNode(Collection tableMappings, Locator JavaDoc locator)
298         throws RepositoryException
299         {
300             addTuples(tableMappings, locator);
301             setLocation(locator);
302         }
303
304         public void clear()
305         {
306             tuples.clear();
307             saved = false;
308             line = -1;
309             column = -1;
310         }
311         
312         public boolean hasTuples()
313         {
314             return (tuples != null) && (tuples.size() != 0);
315         }
316         
317         public void addDefaultTuple(CollectionMappingInfo mappingInfo, Locator JavaDoc locator)
318         throws RepositoryException
319         {
320             // substitute the current default mapping view
321
TableMapping tm = mappingInfo.getTableMapping();
322             tupleFactories[tm.getTableIndex()].setMapping(tm);
323             addTuples(Collections.singletonList(tm), locator);
324         }
325         
326         public void addTuples(Collection tableMappings, Locator JavaDoc locator)
327         {
328             if (tableMappings != null)
329             {
330                 // Allocate tuples for node
331
if (tuples == null)
332                     tuples = new ArrayList(tableMappings.size());
333                 
334                 Iterator it = tableMappings.iterator();
335                 TableMapping table = null;
336                 while (it.hasNext())
337                 {
338                     table = (TableMapping)it.next();
339                     tuples.add(getTupleFactory(table.getTableIndex()).newTuple(locator));
340                 }
341             }
342         }
343             
344
345         public void setLocation(Locator JavaDoc locator)
346         {
347             if (locator != null)
348             {
349                 line = locator.getLineNumber();
350                 column = locator.getColumnNumber();
351             }
352         }
353         
354         public void save() throws XMLDBCException
355         {
356             /* save tuples */
357             try {
358                 if (tuples != null)
359                 {
360                     int len = tuples.size();
361                     for (int i = 0; i < len; i++)
362                     {
363                         ((Tuple)tuples.get(i)).save();
364                     }
365                 }
366             }
367             catch (RepositoryException e) {
368                 throw new StorageException(e, new Locator JavaDoc() {
369                         public String JavaDoc getPublicId() { return null;}
370                         public String JavaDoc getSystemId() { return null;}
371                         public int getLineNumber() { return line;}
372                         public int getColumnNumber() { return column;}
373                     });
374             }
375             /* mark for removal */
376             saved = true;
377         }
378         
379         public void discardEmpty()
380         {
381             if (tuples != null)
382             {
383                 int len = tuples.size();
384                 Tuple tuple;
385                 for (int i = 0; i < len; i++)
386                 {
387                     tuple = (Tuple)tuples.get(i);
388                     if (tuple.isEmpty())
389                         tuple.setDiscarded();
390                 }
391             }
392        }
393         
394         public void changePathSign()
395         {
396             if (tuples != null)
397             {
398                 int len = tuples.size();
399                 Tuple tuple;
400                 for (int i = 0; i < len; i++)
401                 {
402                     ((Tuple)tuples.get(i)).changePathSign();
403                 }
404             }
405         }
406         
407         public void restore()
408         {
409             if (tuples != null)
410             {
411                 int len = tuples.size();
412                 Tuple tuple;
413                 for (int i = 0; i < len; i++)
414                 {
415                     tuple = (Tuple)tuples.get(i);
416                     tupleFactories[tuple.tableIndex].setTuple(tuple);
417                 }
418             }
419         }
420         
421         void complete() throws XMLDBCException
422         {
423             if (tuples != null)
424             {
425                 int len = tuples.size();
426                 for (int i = 0; i < len; i++)
427                 {
428                     ((Tuple)tuples.get(i)).complete();
429                 }
430             }
431         }
432         
433         /** Check that all tuples are ready (completed) and that all tuples
434          * which this node tuples are dependant are stored.
435          */

436         public boolean isReady() throws XMLDBCException
437         {
438             boolean ready = true;
439             
440             if (tuples != null)
441             {
442                 int len = tuples.size();
443                 for (int i = 0; ready && (i < len); i++)
444                 {
445                     ready = (ready && ((Tuple)tuples.get(i)).isReady());
446                 }
447             }
448             
449             return ready;
450         }
451         
452         public boolean isDiscardable() { return saved;}
453     }
454     
455     ////////////////////////////////////////////////////////////////////
456
// TUPLE FACTORY
457
////////////////////////////////////////////////////////////////////
458
public class TupleFactory
459     {
460         private static final String JavaDoc RCSRevision = "$Revision: 1.6 $";
461         private static final String JavaDoc RCSName = "$Name: $";
462         TableMapping mapping = null; // table mapping corresponding to the element
463
private Tuple currentTuple = null; // tuple being built
464
// TO REMOVE ? private int parametersToBeFilled; // number of parameters still missing,
465
// equal to optionalParameters if ready to be saved
466
private PreparedStatement JavaDoc OIDStmt = null; // JDBC statement for value OIDs
467
private PreparedStatement JavaDoc insertStmt = null; // JDBC statement for values
468
private PreparedStatement JavaDoc selectStmt = null; // JDBC statement for reading values
469
private PreparedStatement JavaDoc updateStmt = null; // JDBC statement for reading values
470

471         TupleFactory(MappingInfo mapStmts, AbstractConnection connection) throws SQLException JavaDoc, RepositoryException
472         {
473             this.mapping = mapStmts.getTableMapping();
474             
475             /* Initialize JDBC statements & parameter SQL types */
476             if (!mapping.isClustered())
477                 OIDStmt = connection.getConnection().prepareStatement(mapStmts.getOIDInsertStatement());
478             
479             insertStmt = connection.getConnection().prepareStatement(mapStmts.getInsertStatement());
480             
481             int action = mapping.getAction();
482             if ((mapping.getSelectColumnCount() != 0) && ((action == MappingConstants.SELECT)
483                 || (action == MappingConstants.CHECK) || (action == MappingConstants.UPDATE)))
484                 selectStmt = connection.getConnection().prepareStatement(mapStmts.getSelectStatement());
485             if ((mapping.getUpdateColumnCount() != 0) && (action == MappingConstants.UPDATE))
486                 updateStmt = connection.getConnection().prepareStatement(mapStmts.getUpdateStatement());
487             
488         }
489         
490         TableMapping getMapping()
491         {
492             return mapping;
493         }
494         PreparedStatement JavaDoc getOIDStmt()
495         {
496             return OIDStmt;
497         }
498         PreparedStatement JavaDoc getInsertStmt()
499         {
500             return insertStmt;
501         }
502         PreparedStatement JavaDoc getUpdateStmt()
503         {
504             return updateStmt;
505         }
506          
507         void setMapping(TableMapping mapping)
508         {
509             this.mapping = mapping;
510         }
511          
512         Tuple newTuple(Locator JavaDoc locator)
513         {
514             // Allocate new tuple
515
currentTuple = new Tuple(mapping.getTableIndex(), mapping.getColumnMappingCount(), mapping.getOIDTableColumnCount(), mapping.getSelectColumnCount(), mapping.getUpdateColumnCount(), locator);
516             
517             // Initialize values
518
Iterator it = mapping.initParameters().iterator();
519             ColumnMapping column;
520             Object JavaDoc data;
521             int refIndex;
522             
523             while (it.hasNext())
524             {
525                 column = (ColumnMapping)it.next();
526                 data = column.getInitGenerator().getValue(context);
527                 
528                 currentTuple.insertParamList[column.getInsertColumnIndex()] = data;
529                 if ((OIDStmt != null) && column.isInJoin())
530                     currentTuple.OIDParamList[column.getJoinColumnIndex()] = data;
531                 if ((selectStmt != null) && (column.getSelectColumnIndex() !=-1))
532                 {
533                     currentTuple.selectParamList[column.getSelectColumnIndex()] = data;
534                     currentTuple.selectParamCount++;
535                 }
536                 if ((updateStmt != null) && (column.getUpdateColumnIndex() !=-1))
537                     currentTuple.updateParamList[column.getUpdateColumnIndex()] = data;
538                 
539             }
540             
541             ColumnMapping[] cms = mapping.getColumnMappings();
542             for (int i = 0; i < cms.length; i++)
543             {
544                 /* create depency within tables from ref generators */
545                 // NOTE :
546
// 1. table-column mappings are real column mappings and they can have default generators
547
// because they are nullable or have a default value. But are not in init generators if
548
// they do not have default (they will be called when node will be encountered).
549
// 2. They won't reference the subelement as a master tuple (since the referenced tuple does
550
// not exist yet), but it does not really matter since the current tuple will be finished
551
// after the refernced tuple by construction.
552
refIndex = cms[i].getTableRefIndex();
553                 if (refIndex != -1)
554                     currentTuple.addMasterTuple(tupleFactories[refIndex].getTuple());
555                     // tuple is null in the table-colum maping case and will be ignored
556
}
557
558             // Set DocOID & OID
559
if (OIDStmt != null)
560             {
561                 currentTuple.OIDParamList[0] = new Long JavaDoc(context.getUOID());
562                 currentTuple.OIDParamList[1] = new Integer JavaDoc(context.getPathOID());
563             }
564             
565             return currentTuple; // for buffer storing
566
}
567         
568         void saveTuple(Tuple tuple, int line, int column) throws SQLException JavaDoc, XMLDBCException
569         {
570             if (log.isDebugEnabled())
571                 log.debug("Saving tuple:\n" + tuple);
572             try
573             {
574                 // according to access mode : update operations
575
switch (mapping.getAction())
576                 {
577                     case MappingConstants.UPDATE :
578                         if (tuple.isInbase())
579                             performUpdate(tuple, line, column);
580                         else
581                             performInsert(tuple, line, column);
582                         break;
583                         
584                     case MappingConstants.CHECK :
585                         if (!tuple.isInbase())
586                             performInsert(tuple, line, column);
587                         break;
588                         
589                     case MappingConstants.INSERT :
590                         // Insert directly in the table
591
// Fills values statement with parameters values
592
performInsert(tuple, line, column);
593                         break;
594                         
595                     default :
596                 }
597                 
598                 /* OID insertion */
599                 // Fills OID statement with parameters values
600
if (OIDStmt != null)
601                 {
602                     int i = 0;
603                     // filling UOID & PathID (that do not have column Mappings
604
try
605                     {
606                         for (; i < 2; i++)
607                         {
608                             OIDStmt.setObject(i+1, tuple.OIDParamList[i]);
609                         }
610                         // filling key columns
611
for (; i < tuple.OIDParamList.length; i++)
612                         {
613                             mapping.getJoinColumns()[i-2].getTypeInfo().setParameter(
614                             OIDStmt,
615                             i+1,
616                             tuple.OIDParamList[i],
617                             connection,
618                             overrideEmptyString,
619                             errorHandler
620                             );
621                         }
622                     }
623                     catch (Exception JavaDoc e)
624                     {
625                         throw new RepositoryException(RepositoryException.DB_ERROR, "Error while setting data in column " + (i+1) + " of :\n" + tuple, e);
626                     }
627                     // Execute statement
628
batcher.addBatch(OIDStmt, line, column);
629                 }
630             }
631             catch (SQLException JavaDoc e)
632             {
633                 throw new RepositoryException(RepositoryException.DB_ERROR, "Error while saving tuple :\n" + tuple, e);
634             }
635         }
636         
637         private void performInsert(Tuple tuple, int line, int column) throws SQLException JavaDoc, RepositoryException
638         {
639             int i = 0;
640             try
641             {
642                 ColumnMapping[] columns = mapping.getColumnMappings();
643                 ColumnMapping c;
644                 for (i = 0; i < columns.length; i++)
645                 {
646                     c = columns[i];
647                     c.getTypeInfo().setParameter(
648                         insertStmt,
649                         c.getInsertColumnIndex() + 1,
650                         tuple.insertParamList[c.getInsertColumnIndex()],
651                         connection,
652                         overrideEmptyString,
653                         errorHandler);
654                 }
655             }
656             catch (Exception JavaDoc e)
657             {
658                 throw new RepositoryException(
659                     RepositoryException.DB_ERROR,
660                     "Error while setting data in column "
661                         + (i + 1)
662                         + " of :\n"
663                         + tuple,
664                     e);
665             }
666             // Execute statement
667
batcher.addBatch(insertStmt, line, column);
668         }
669         
670         private void performUpdate(Tuple tuple, int line, int column) throws SQLException JavaDoc, RepositoryException // TO RETROFIT TO 1.0 ?
671
{
672             if (updateStmt != null)
673             {
674                 int i = 0;
675                 try
676                 {
677                     // Fills values statement with parameters values
678
for (i = 0; i < tuple.updateParamList.length; i++)
679                     {
680                         mapping.getUpdateColumns()[i].getTypeInfo().setParameter(
681                             updateStmt,
682                             i+1,
683                             tuple.updateParamList[i],
684                             connection,
685                             overrideEmptyString,
686                             errorHandler
687                             );
688                     }
689                 }
690                 catch (Exception JavaDoc e)
691                 {
692                     throw new RepositoryException(RepositoryException.DB_ERROR, "Error in column " + (i+1) + " while updating tuple :\n" + tuple, e);
693                 }
694                 int j = 0;
695                 try
696                 {
697                     for (j = 0; j < tuple.selectParamList.length; j++)
698                     {
699                         mapping.getSelectColumns()[j].getTypeInfo().setParameter(
700                             updateStmt,
701                             i+j+1,
702                             tuple.selectParamList[j],
703                             connection,
704                             overrideEmptyString,
705                             errorHandler
706                             );
707                     }
708                 }
709                 catch (Exception JavaDoc e)
710                 {
711                     throw new RepositoryException(RepositoryException.DB_ERROR, "Error while setting data in column " + (i+j+1) + " of :\n" + tuple, e);
712                 }
713                 // Execute statement
714
batcher.addBatch(updateStmt, line, column);
715             }
716             else
717                 throw new RepositoryException(RepositoryException.MAPPING_CONSISTENCY_ERROR,
718                 "The update statement is missing for "
719                 + mapping.getTableName()
720                 + " table in mapping information.");
721         }
722         
723         Object JavaDoc getParameter(int index)
724         {
725             if (currentTuple != null) // meens valid from a mapping point of view
726
return currentTuple.insertParamList[index];
727             else
728                 return null;
729         }
730         
731         void addMasterTuple(Tuple tuple)
732         {
733             currentTuple.addMasterTuple(tuple);
734         }
735         
736         Tuple getTuple() { return currentTuple;}
737         
738         void setTuple(Tuple tuple) { currentTuple = tuple;}
739         
740         /**
741          * If action is CHECK, SELECT or UPDATE fills the tuple with the row in the database.
742          */

743         // TODO : do it when sending it to batcher but what to do with references ?
744
void updateFromDatabase(Tuple currentTuple, int selectParamCount)
745         throws XMLDBCException
746         {
747             if ((selectParamCount < mapping.getSelectColumnCount())
748                 || (mapping.getAction() == MappingConstants.INSERT) // All other actions need to query the db
749
|| currentTuple.isInbase()) // already retrieved
750
return; // the tuple is not filled enough for selection
751

752             // Flush needed for the case of intra-document redundancy
753
// TO IMPROVE : check when mutiple use of the same table mapping in a document
754
// to perform a selective flush or keep a list of unflushed tuples...
755
log.debug("Flush triggered for select");
756             batcher.flush();
757             
758             ResultSet JavaDoc rs = null;
759             
760             try
761             {
762                 // according to access mode : selection operation
763
if (selectStmt != null)
764                 {
765                     // Fills select statement with parameters values
766
int i = 0;
767                     try
768                     {
769                         for (; i < currentTuple.selectParamList.length; i++)
770                         {
771                             mapping.getSelectColumns()[i].getTypeInfo().setParameter(
772                             selectStmt,
773                             i+1,
774                             currentTuple.selectParamList[i],
775                             connection,
776                             overrideEmptyString,
777                             errorHandler
778                             );
779                         }
780                     }
781                     catch (Exception JavaDoc e)
782                     {
783                         throw new RepositoryException(RepositoryException.DB_ERROR,
784                             "Error while setting data in column " + (i+1) + " of :\n" + currentTuple, e);
785                     }
786                     // Fetch results and put it in the insert parameter list
787
rs = selectStmt.executeQuery();
788                 }
789                 else
790                     throw new RepositoryException(RepositoryException.MAPPING_CONSISTENCY_ERROR,
791                     "The select statement is missing for "
792                     + mapping.getTableName()
793                     + " table in mapping information.");
794                 
795                 /* update the tuple */
796                 if (rs.next()) // Take the first
797
{
798                     currentTuple.foundInBase(); // Mark the tuple is present in the database
799
int joinIndex, updateIndex;
800                     ColumnMapping cm = null;
801                     Object JavaDoc o = null;
802                     // update the insert and the OID statement (+ references) with row read in the database
803
for (int i = 0; i < mapping.getFetchColumnCount(); i++)
804                     {
805                         cm = mapping.getFetchColumns()[i];
806                         joinIndex = cm.getJoinColumnIndex(); // because column index is also the index in table's mapping list of columns mappings
807
o = rs.getObject(i+1);
808                         if (mapping.getAction() == MappingConstants.UPDATE) { // Need to update tuple (CHECK or SELECT)
809
if (joinIndex != -1) // update only the key columns
810
currentTuple.insertParamList[cm.getInsertColumnIndex()] = o;
811                             updateIndex = cm.getUpdateColumnIndex();
812                             if (!cm.updateColumnWhenMissing() && updateIndex >= 0 && currentTuple.updateParamList[updateIndex] == null)
813                                 currentTuple.updateParamList[cm.getUpdateColumnIndex()] = o;
814                         }
815                         else
816                             currentTuple.insertParamList[cm.getInsertColumnIndex()] = o;
817                          
818                         // Update the key in the OID table
819
if (joinIndex != -1)
820                             currentTuple.OIDParamList[joinIndex] = currentTuple.insertParamList[cm.getInsertColumnIndex()];
821                     }
822                     if (log.isDebugEnabled()) {
823                         List list = Arrays.asList(currentTuple.insertParamList);
824                         log.debug("Tuple fetched from the database: " + list);
825                     }
826                 }
827                 else if (mapping.getAction() == MappingConstants.SELECT) // no row found
828
throw new RepositoryException(RepositoryException.DB_CONSISTENCY_ERROR, "Couldn't find the tuple corresponding to the SELECT table mapping\n" + currentTuple);
829             }
830             catch (SQLException JavaDoc e) {
831                 throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while reading tuple from the database\n" + currentTuple, e);
832             }
833             finally
834             {
835                 try
836                 {
837                     if (rs != null)
838                         rs.close();
839                 }
840                 catch (SQLException JavaDoc e)
841                 {
842                     throw new RepositoryException(RepositoryException.DB_WARNING, "JDBC error while releasing ressources for table mapping.", e);
843                 }
844             }
845         }
846         
847         public void clear()
848         {
849             currentTuple = null;
850         }
851         
852         public void close() throws RepositoryException
853         {
854             try {
855                 if (OIDStmt != null)
856                 {
857                     OIDStmt.close();
858                     OIDStmt = null;
859                 }
860                 if (insertStmt != null)
861                 {
862                     insertStmt.close();
863                     insertStmt = null;
864                 }
865                 if (selectStmt != null)
866                 {
867                     selectStmt.close();
868                     selectStmt = null;
869                 }
870                 if (updateStmt != null)
871                 {
872                     updateStmt.close();
873                     updateStmt = null;
874                 }
875             }
876             catch (SQLException JavaDoc e) {
877                 throw new RepositoryException(RepositoryException.DB_WARNING, "JDBC error while releasing ressources for table mapping.", e);
878             }
879         }
880     }
881     
882     ////////////////////////////////////////////////////////////////////
883
// TUPLE
884
////////////////////////////////////////////////////////////////////
885

886     public class Tuple
887     {
888         private static final String JavaDoc RCSRevision = "$Revision: 1.6 $";
889         private static final String JavaDoc RCSName = "$Name: $";
890         Object JavaDoc[] insertParamList = null; // list for parameters for the insert statement
891
Object JavaDoc[] OIDParamList = null; // list for parameters for the OID table statement
892
Object JavaDoc[] selectParamList = null; // list for parameters for the select statement
893
Object JavaDoc[] updateParamList = null; // list for parameters for the select statement
894
ArrayList waitingFor = null; // List of tuples which this node is dependent on
895
// in order to be flushed to database
896
int tableIndex; // to identify the factory for saving
897
private int selectParamCount = 0; // Number of parameters filled that are part of the selection key
898
boolean complete = false;
899         boolean discarded = false;
900         boolean empty = true;
901         boolean saved = false;
902         private boolean inBase = false; // The tuple was found in the database
903
int line = -1;
904         int column = -1;
905         
906         Tuple(int tableIndex, int insertSize, int OIDsize, int selectSize, int updateSize, Locator JavaDoc locator)
907         {
908             this.tableIndex = tableIndex;
909             insertParamList = new Object JavaDoc[insertSize];
910             if (OIDsize != 0)
911                 OIDParamList = new Object JavaDoc[OIDsize];
912             if (selectSize != 0)
913                 selectParamList = new Object JavaDoc[selectSize];
914             if (updateSize != 0)
915                 updateParamList = new Object JavaDoc[updateSize];
916             setLocation(locator);
917         }
918
919         public void setLocation(Locator JavaDoc locator)
920         {
921             if (locator != null)
922             {
923                 line = locator.getLineNumber();
924                 column = locator.getColumnNumber();
925             }
926         }
927         
928         void save() throws XMLDBCException
929         {
930             try {
931                 if (!saved && !discarded)
932                 {
933                     tupleFactories[tableIndex].saveTuple(this, line, column);
934                     saved = true;
935                 }
936             }
937             catch (SQLException JavaDoc e) {
938                 throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while saving tuple " + this, e);
939             }
940         }
941         
942         void changePathSign()
943         {
944             // Reinitialize system genrators because may contain path generator
945
Iterator it = tupleFactories[tableIndex].getMapping().initParameters().iterator();
946             ColumnMapping column;
947             Object JavaDoc data;
948             int refIndex;
949             
950             while (it.hasNext())
951             {
952                 column = (ColumnMapping)it.next();
953                 Generator gen = column.getDefaultGenerator();
954                 if (gen instanceof SystemVariableGenerator)
955                 {
956                     data = gen.getValue(context);
957                     
958                     insertParamList[column.getInsertColumnIndex()] = data;
959                     if ((OIDParamList != null) && column.isInJoin())
960                         OIDParamList[column.getJoinColumnIndex()] = data;
961                     if ((selectParamList != null) && (column.getSelectColumnIndex() !=-1))
962                     {
963                         selectParamList[column.getSelectColumnIndex()] = data;
964                         selectParamCount++;
965                     }
966                     if ((updateParamList != null) && (column.getUpdateColumnIndex() !=-1))
967                         updateParamList[column.getUpdateColumnIndex()] = data;
968                 }
969            }
970             
971             // change path ID sign
972
if (OIDParamList != null)
973                 OIDParamList[1] = new Integer JavaDoc(context.getPathOID());
974         }
975
976         
977         /**
978          * The tuple is built. Automatic update is performed from database if needed.
979          */

980         void addColumnMappingData(ColumnMapping column, StorageContext context)
981         throws XMLDBCException
982         {
983             addParameter(column, context);
984             tupleFactories[tableIndex].updateFromDatabase(this, selectParamCount);
985         }
986         
987         private void addParameter(ColumnMapping column, StorageContext context)
988         {
989             empty = false;
990             Object JavaDoc data = column.getGenerator().getValue(context);
991             insertParamList[column.getInsertColumnIndex()] = data;
992             if ((OIDParamList != null) && column.isInJoin())
993                 OIDParamList[column.getJoinColumnIndex()] = data;
994             if ((selectParamList != null) && (column.getSelectColumnIndex() >= 0))
995             {
996                 selectParamList[column.getSelectColumnIndex()] = data;
997                 selectParamCount++;
998             }
999             if ((updateParamList != null) && (column.getUpdateColumnIndex() >= 0))
1000                updateParamList[column.getUpdateColumnIndex()] = data;
1001        }
1002        
1003        /**
1004         * The tuple is filled with generators and passed to the buffer.
1005         * No subsequent update should be performed.
1006         */

1007        void complete() throws XMLDBCException
1008        {
1009            // process ending parameters (generators
1010
Iterator it = tupleFactories[tableIndex].mapping.finalParameters().iterator();
1011            while (it.hasNext())
1012            {
1013                addColumnMappingData((ColumnMapping)it.next(), context);
1014            }
1015
1016            setCompleted();
1017        }
1018        
1019        void addMasterTuple(Tuple tuple)
1020        {
1021            if (tuple != null) {
1022                if (waitingFor == null)
1023                    waitingFor = new ArrayList();
1024                waitingFor.add(tuple);
1025            }
1026        }
1027        /** check that the tuple is complete and that all tuples which it
1028         * depends on are ready (eventually tries to trigger their storage).
1029         **/

1030        public boolean isReady() throws XMLDBCException
1031        {
1032            if (discarded || saved)
1033                return true;
1034            if (complete)
1035            {
1036                if ((waitingFor == null) || (waitingFor.size() == 0))
1037                    return true;
1038                else // try to flush dependent tuples
1039
{
1040                    boolean ready = true;
1041                    Iterator it = waitingFor.iterator();
1042                    Tuple waitedTuple;
1043                    while (it.hasNext())
1044                    {
1045                        waitedTuple = (Tuple)it.next();
1046                        // if ready, save it
1047
if (waitedTuple.isReady())
1048                        {
1049                            waitedTuple.save();
1050                            it.remove();
1051                        }
1052                        else
1053                           ready = false; // one is enough
1054
}
1055                    return ready;
1056                }
1057            }
1058            else
1059                return false;
1060        }
1061
1062        public void setCompleted()
1063        {
1064            complete = true;
1065        }
1066        
1067        public void setDiscarded()
1068        {
1069            discarded = true;
1070        }
1071        
1072        public void foundInBase()
1073        {
1074            inBase = true;
1075        }
1076        
1077        public boolean isInbase()
1078        {
1079            return inBase;
1080        }
1081        public boolean isEmpty()
1082        {
1083            return empty;
1084        }
1085        public String JavaDoc toString()
1086        {
1087            StringWriter JavaDoc sw = new StringWriter JavaDoc();
1088            Tabulator tab = new Tabulator(sw, 160, new int[] {0, 15});
1089
1090            /* table display */
1091            tab.addItem("Table:");
1092            tab.addItem(tupleFactories[tableIndex].mapping.getTableName());
1093            
1094            /* Location */
1095            tab.addItem("XML location:");
1096            tab.addItem("line " + line + ", column " + column);
1097            
1098            TableMapping tm = tupleFactories[tableIndex].mapping;
1099            
1100            /* Column display */
1101            tab.addItem("Columns:");
1102            List list = Arrays.asList(tm.getColumnMappings());
1103            tab.addItem(list);
1104            
1105            /* Values display */
1106            tab.addItem("Values:");
1107            list = Arrays.asList(insertParamList);
1108            tab.addItem(list);
1109            if (log.isDebugEnabled())
1110            {
1111                /* Java types display */
1112                tab.addItem("Java types:");
1113                tab.addItem(diplayListClasses(list));
1114                if (!tm.isClustered())
1115                {
1116                    /* OID values display */
1117                    tab.addItem("OID:");
1118                    list = Arrays.asList(OIDParamList);
1119                    tab.addItem(list);
1120                    /* Java types display */
1121                    tab.addItem("Java types:");
1122                    tab.addItem(diplayListClasses(list));
1123                }
1124            }
1125            return sw.toString();
1126        }
1127
1128        private StringBuffer JavaDoc diplayListClasses(List list)
1129        {
1130            StringBuffer JavaDoc display = new StringBuffer JavaDoc();
1131            Object JavaDoc o;
1132            display.append("");
1133            for (int i = 0; i < list.size() ; i++)
1134            {
1135                if (i == 0)
1136                    display.append("[");
1137                else
1138                    display.append(", ");
1139                o = list.get(i);
1140                if (o == null)
1141                    display.append("null");
1142                else
1143                    display.append(o.getClass().getName());
1144            }
1145            display.append("]");
1146            return display;
1147        }
1148    }
1149}
1150
Popular Tags