KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > mapper > dbms > JDBCBatcher


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

22
23 /*
24  * JDBCBatcher.java
25  *
26  * Created on 30 mai 2001, 10:28
27  */

28
29 package org.xquark.mapper.dbms;
30
31 import java.io.StringWriter JavaDoc;
32 import java.sql.BatchUpdateException JavaDoc;
33 import java.sql.PreparedStatement JavaDoc;
34 import java.sql.SQLException JavaDoc;
35 import java.util.*;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.xquark.mapper.RepositoryException;
40 import org.xquark.mapper.util.Tabulator;
41
42 /** Manage JDBC 2.0 batch feature with referential integrity
43  * and automatic flush handling.
44  * <p><B>Warning :</B> dependency is handled only as chains, not trees.</p>
45  *
46  */

47 public class JDBCBatcher
48 {
49     private static final String JavaDoc RCSRevision = "$Revision: 1.3 $";
50     private static final String JavaDoc RCSName = "$Name: $";
51
52     private static Log log = LogFactory.getLog("internal." + JDBCBatcher.class.getName());
53
54     final static int DEFAULT_BATCH_SIZE = 20;
55     
56     /* key is the statement, value is StatementInfo */
57     HashMap statements;
58     
59     /* lists of dependent statements, less dependent 1st*/
60     List statementLists;
61     
62     AbstractConnection conn;
63     
64     protected boolean autoFlush = true;
65     
66     /** Creates new JDBCBatcher */
67     public JDBCBatcher(AbstractConnection connection, boolean autoFlush)
68     {
69         statements = new HashMap();
70         statementLists = new ArrayList();
71         conn = connection;
72         this.autoFlush = autoFlush;
73     }
74     
75     /* Add an independent statement (a new list is created) with the default
76      * batch size.
77      * @return the index of the list created
78      */

79     public int addStatement(PreparedStatement JavaDoc stmt, String JavaDoc tableName)
80     {
81         return addStatement(stmt, tableName, DEFAULT_BATCH_SIZE);
82     }
83     
84     /* Add an independent statement (a new list is created)
85      * @return the index of the list created
86      */

87     public int addStatement(PreparedStatement JavaDoc stmt, String JavaDoc tableName, int batchSize)
88     {
89         
90         return addStatement(- 1, stmt, tableName, batchSize);
91     }
92     
93     /* add a statement at the end of a specific statement list
94      * @param listNumber
95      */

96     public int addStatement(int listIndex, PreparedStatement JavaDoc stmt, String JavaDoc tableName, int batchSize)
97     {
98         if (stmt == null)
99             return -1;
100         if (listIndex == -1)
101         {
102             listIndex = statementLists.size();
103             statementLists.add(new ArrayList());
104         }
105         StatementInfo info = new StatementInfo(batchSize,
106         listIndex,
107         ((List)statementLists.get(listIndex)).size(),
108         stmt, tableName);
109         statements.put(stmt, info);
110         ((List)statementLists.get(listIndex)).add(info);
111         return listIndex;
112     }
113     
114     /* returns true if an automatic flush has been performed */
115     public boolean addBatch(PreparedStatement JavaDoc stmt, int line, int column) throws RepositoryException
116     {
117         StatementInfo info = (StatementInfo)statements.get(stmt);
118         try
119         {
120             if (info.batchSize != 1) // else batch desactivated for debug (statement executed in flush)
121
conn.addBatch(stmt);
122         }
123         catch (SQLException JavaDoc e)
124         {
125             throw new RepositoryException(
126                 RepositoryException.DB_ERROR,
127                 "JDBC error while inserting tuple in batch.",
128                 e);
129         }
130         if (info.inc(line, column)) // needs automatic flush
131
{
132             if (log.isDebugEnabled())
133                 log.debug("JDBC batcher automatic flush triggered by\n" + info + '\n' + this);
134             flush(info.getListIndex(), info.getIndex());
135             return true;
136         }
137         else
138         {
139             if (log.isDebugEnabled())
140                 log.debug("Add row to batch\n" + info);
141             return false;
142         }
143     }
144     
145     /* returns true if an automatic flush has been performed */
146     public boolean addBatch(PreparedStatement JavaDoc stmt) throws RepositoryException
147     {
148         return addBatch(stmt, -1, -1);
149     }
150     
151     public void setAutoFlush(boolean mode)
152     {
153         autoFlush = mode;
154     }
155     
156     public void flush() throws RepositoryException
157     {
158         if (log.isDebugEnabled())
159             log.debug("General JDBC batcher Forced Flush\n" + this);
160         Iterator it = statementLists.iterator();
161         while (it.hasNext())
162         {
163             flush((List)it.next());
164         }
165     }
166     
167     public void flush(int listIndex) throws RepositoryException
168     {
169         flush((List)statementLists.get(listIndex));
170     }
171     
172     private void flush(List stmtList) throws RepositoryException
173     {
174         for(int i = 0; i < stmtList.size(); i++)
175         {
176             flush((StatementInfo)stmtList.get(i));
177         }
178     }
179     
180     public String JavaDoc toString()
181     {
182         StringWriter JavaDoc sw = new StringWriter JavaDoc();
183         Tabulator tab = new Tabulator(sw, 79, new int[] {0, 15, 30, 45, 60});
184         tab.addItem("Table");
185         tab.addItem("Batch size");
186         tab.addItem("Batch count");
187         tab.addItem("List index");
188         tab.addItem("Stmt index");
189         
190         Iterator it = statementLists.iterator();
191         List list;
192         StatementInfo si;
193         
194         while (it.hasNext())
195         {
196             list = (List)it.next();
197             for(int i = 0; i < list.size(); i++)
198             {
199                 si = (StatementInfo)list.get(i);
200                 tab.addItem(si.tableName);
201                 tab.addItem(si.batchSize);
202                 tab.addItem(si.batchCount);
203                 tab.addItem(si.listIndex);
204                 tab.addItem(si.indexStatement);
205             }
206             tab.newLine();
207         }
208         return sw.toString();
209     }
210     
211     public void flush(int indexList, int index) throws RepositoryException
212     {
213         flush((List)statementLists.get(indexList), index);
214     }
215     
216     private void flush(List stmtList, int index) throws RepositoryException
217     {
218         for(int i = 0; i <= index; i++)
219         {
220             flush((StatementInfo)stmtList.get(i));
221         }
222     }
223     
224     public void flush(PreparedStatement JavaDoc stmt) throws RepositoryException
225     {
226         StatementInfo info = (StatementInfo)statements.get(stmt);
227         flush(info.getListIndex(), info.getIndex());
228     }
229     
230     /* Elementary method : no cascading */
231     private void flush(StatementInfo info) throws RepositoryException
232     {
233         int [] result = null;
234         try
235         {
236             if (info.getCount() > 0)
237             {
238                 if (info.batchSize == 1)
239                     info.getStatement().execute(); // in order to debug
240
else
241                     result = conn.executeBatch(info.getStatement());
242             }
243         }
244         catch (BatchUpdateException JavaDoc e)
245         {
246             result = e.getUpdateCounts();
247             int errorIndex = -1;
248             for (errorIndex = 0; (errorIndex < result.length) && (result[errorIndex] != -3); errorIndex++);
249             
250             String JavaDoc message = "JDBC error while executing batch on table " + info.getTableName();
251             LocatorImpl location = null;
252             
253             if (errorIndex >= 0)
254                 location = info.getLocator(errorIndex);
255             
256             if (location == null)
257                 throw new RepositoryException(RepositoryException.DB_ERROR, message, e);
258             else
259                 throw new RepositoryException(RepositoryException.DB_ERROR, message + " " + location, e);
260         }
261         catch (SQLException JavaDoc e)
262         {
263             throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while executing batch on table " + info.getTableName(), e);
264         }
265         finally
266         {
267             info.reset();
268         }
269     }
270     
271     public void clear() throws SQLException JavaDoc
272     {
273         if (log.isDebugEnabled())
274             log.debug("Clear batcher\n" + this);
275         statements.clear();
276         statementLists.clear();
277     }
278     
279     public void reset() throws SQLException JavaDoc
280     {
281         if (log.isDebugEnabled())
282             log.debug("Reset batcher\n" + this);
283         int max = statementLists.size();
284         for (int i= 0; i < max; i++)
285             reset(i);
286     }
287     
288     public void reset(int i) throws SQLException JavaDoc
289     {
290         Iterator it = ((List)statementLists.get(i)).iterator();
291         StatementInfo info;
292         while (it.hasNext())
293         {
294             info = (StatementInfo)it.next();
295             info.getStatement().clearBatch();
296             info.reset();
297         }
298     }
299     
300     public void remove(PreparedStatement JavaDoc stmt)
301     {
302         StatementInfo info = (StatementInfo)statements.get(stmt);
303         ((List)statementLists.get(info.getListIndex())).remove(info.getIndex());
304         statements.remove(stmt);
305     }
306     
307     public void close() throws SQLException JavaDoc
308     {
309         if (statements != null)
310         {
311             clear();
312             statements = null;
313             statementLists = null;
314             conn = null;
315         }
316     }
317     
318     private class StatementInfo
319     {
320         private int batchSize;
321         private int batchCount = 0;
322         private List locators = new ArrayList();
323         private int listIndex;
324         private int indexStatement;
325         private PreparedStatement JavaDoc statement;
326         private String JavaDoc tableName;
327         StatementInfo(int batchSize, int listIndex, int indexStatement, PreparedStatement JavaDoc statement, String JavaDoc tableName)
328         {
329             this.batchSize = batchSize;
330             this.listIndex = listIndex;
331             this.indexStatement = indexStatement;
332             this.statement = statement;
333             this.tableName = tableName;
334         }
335         boolean inc(int line, int column)
336         {
337             if ((line >= 0) || (column >= 0))
338                 locators.add(new LocatorImpl(line, column));
339             batchCount++;
340             return (autoFlush && (batchCount == batchSize || log.isDebugEnabled())); // Setting batch size to 1 is needed for debug.
341
}
342         void reset()
343         {
344             batchCount = 0;
345             locators.clear();
346         }
347         LocatorImpl getLocator(int index)
348         {
349             if (index >= locators.size())
350                 return null;
351             else
352                 return (LocatorImpl)locators.get(index);
353         }
354         int getCount()
355         {return batchCount;}
356         int getListIndex()
357         {return listIndex;}
358         int getIndex()
359         {return indexStatement;}
360         String JavaDoc getTableName()
361         {return tableName;}
362         PreparedStatement JavaDoc getStatement()
363         {return statement;}
364         public String JavaDoc toString()
365         {
366             return tableName + "\t"+ batchSize + "\t" + batchCount + "\t" + listIndex + "\t" + indexStatement;
367         }
368     }
369     
370     private class LocatorImpl
371     {
372         int line;
373         int column;
374         
375         LocatorImpl(int line, int column)
376         {
377             this.line = line;
378             this.column = column;
379         }
380         
381         public String JavaDoc toString()
382         {
383             return "(line " + line + ", column " + column + ")";
384         }
385     }
386 }
387
Popular Tags