KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > util > batch > BatchConnection


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

17
18 import java.lang.reflect.Proxy JavaDoc;
19 import java.sql.Connection JavaDoc;
20 import java.sql.PreparedStatement JavaDoc;
21 import java.sql.SQLException JavaDoc;
22 import java.sql.Statement JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29
30 import org.apache.ojb.broker.PersistenceBroker;
31 import org.apache.ojb.broker.metadata.ClassDescriptor;
32 import org.apache.ojb.broker.metadata.CollectionDescriptor;
33 import org.apache.ojb.broker.metadata.DescriptorRepository;
34 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
35 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
36 import org.apache.ojb.broker.util.WrappedConnection;
37
38 /**
39  * The implementation of {@link java.sql.Connection} which
40  * automatically gathers INSERT, UPDATE and DELETE
41  * PreparedStatements into batches.
42  *
43  * @author Oleg Nitz (<a HREF="mailto:olegnitz@apache.org">olegnitz@apache.org</a>)
44  * @version $Id: BatchConnection.java,v 1.20.2.1 2005/12/21 22:27:48 tomdz Exp $
45  */

46 public class BatchConnection extends WrappedConnection
47 {
48     private static final int MAX_COUNT = 100;
49
50     /**
51      * Maps PBKey to another HashMap,
52      * which maps table name to List of related tables (N:1 or 1:1)
53      */

54     private static HashMap JavaDoc _pbkeyToFKInfo = new HashMap JavaDoc();
55
56     private boolean _useBatchInserts = true;
57     private HashMap JavaDoc _statements = new HashMap JavaDoc();
58     private ArrayList JavaDoc _order = new ArrayList JavaDoc();
59     private HashMap JavaDoc _fkInfo;
60     private HashSet JavaDoc _deleted;
61     private HashSet JavaDoc _dontInsert;
62     private HashSet JavaDoc _touched = new HashSet JavaDoc();
63     private int count = 0;
64     private JdbcConnectionDescriptor m_jcd;
65
66     public BatchConnection(Connection JavaDoc conn, PersistenceBroker broker)
67     {
68         super(conn);
69         m_jcd = broker.serviceConnectionManager().getConnectionDescriptor();
70         _fkInfo = (HashMap JavaDoc) _pbkeyToFKInfo.get(broker.getPBKey());
71         if (_fkInfo != null)
72         {
73             return;
74         }
75
76         DescriptorRepository repos = broker.getDescriptorRepository();
77         _fkInfo = new HashMap JavaDoc();
78         for (Iterator JavaDoc it = repos.iterator(); it.hasNext();)
79         {
80             ClassDescriptor desc = (ClassDescriptor) it.next();
81             List JavaDoc ordList = desc.getObjectReferenceDescriptors();
82             if (!ordList.isEmpty())
83             {
84                 HashSet JavaDoc fkTables = getFKTablesFor(desc.getFullTableName());
85                 for (Iterator JavaDoc it2 = ordList.iterator(); it2.hasNext();)
86                 {
87                     ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) it2.next();
88                     ClassDescriptor oneDesc = repos.getDescriptorFor(ord.getItemClass());
89                     fkTables.addAll(getFullTableNames(oneDesc, repos));
90                 }
91             }
92
93             List JavaDoc codList = desc.getCollectionDescriptors();
94             for (Iterator JavaDoc it2 = codList.iterator(); it2.hasNext();)
95             {
96                 CollectionDescriptor cod = (CollectionDescriptor) it2.next();
97                 ClassDescriptor manyDesc = repos.getDescriptorFor(cod.getItemClass());
98                 if (cod.isMtoNRelation())
99                 {
100                     HashSet JavaDoc fkTables = getFKTablesFor(cod.getIndirectionTable());
101                     fkTables.addAll(getFullTableNames(desc, repos));
102                     fkTables.addAll(getFullTableNames(manyDesc, repos));
103                 }
104                 else
105                 {
106                     HashSet JavaDoc manyTableNames = getFullTableNames(manyDesc, repos);
107                     for (Iterator JavaDoc it3 = manyTableNames.iterator(); it3.hasNext();)
108                     {
109                         HashSet JavaDoc fkTables = getFKTablesFor((String JavaDoc) it3.next());
110                         fkTables.addAll(getFullTableNames(desc, repos));
111                     }
112                 }
113             }
114         }
115         _pbkeyToFKInfo.put(broker.getPBKey(), _fkInfo);
116     }
117
118     private HashSet JavaDoc getFKTablesFor(String JavaDoc tableName)
119     {
120         HashSet JavaDoc fkTables = (HashSet JavaDoc) _fkInfo.get(tableName);
121
122         if (fkTables == null)
123         {
124             fkTables = new HashSet JavaDoc();
125             _fkInfo.put(tableName, fkTables);
126         }
127         return fkTables;
128     }
129
130     private HashSet JavaDoc getFullTableNames(ClassDescriptor desc, DescriptorRepository repos)
131     {
132         String JavaDoc tableName;
133         HashSet JavaDoc tableNamesSet = new HashSet JavaDoc();
134         Collection JavaDoc extents = desc.getExtentClasses();
135
136         tableName = desc.getFullTableName();
137         if (tableName != null)
138         {
139             tableNamesSet.add(tableName);
140         }
141         for (Iterator JavaDoc it = extents.iterator(); it.hasNext();)
142         {
143             Class JavaDoc extClass = (Class JavaDoc) it.next();
144             ClassDescriptor extDesc = repos.getDescriptorFor(extClass);
145             tableName = extDesc.getFullTableName();
146             if (tableName != null)
147             {
148                 tableNamesSet.add(tableName);
149             }
150         }
151         return tableNamesSet;
152     }
153
154     public void setUseBatchInserts(boolean useBatchInserts)
155     {
156         _useBatchInserts = useBatchInserts;
157     }
158
159     /**
160      * Remember the order of execution
161      */

162     void nextExecuted(String JavaDoc sql) throws SQLException JavaDoc
163     {
164         count++;
165
166         if (_order.contains(sql))
167         {
168             return;
169         }
170
171         String JavaDoc sqlCmd = sql.substring(0, 7);
172         String JavaDoc rest = sql.substring(sqlCmd.equals("UPDATE ") ? 7 // "UPDATE "
173
: 12); // "INSERT INTO " or "DELETE FROM "
174
String JavaDoc tableName = rest.substring(0, rest.indexOf(' '));
175         HashSet JavaDoc fkTables = (HashSet JavaDoc) _fkInfo.get(tableName);
176
177         // we should not change order of INSERT/DELETE/UPDATE
178
// statements for the same table
179
if (_touched.contains(tableName))
180         {
181             executeBatch();
182         }
183         if (sqlCmd.equals("INSERT "))
184         {
185             if (_dontInsert != null && _dontInsert.contains(tableName))
186             {
187                 // one of the previous INSERTs contained a table
188
// that references this table.
189
// Let's execute that previous INSERT right now so that
190
// in the future INSERTs into this table will go first
191
// in the _order array.
192
executeBatch();
193             }
194         }
195         else
196         //if (sqlCmd.equals("DELETE ") || sqlCmd.equals("UPDATE "))
197
{
198             // We process UPDATEs in the same way as DELETEs
199
// because setting FK to NULL in UPDATE is equivalent
200
// to DELETE from the referential integrity point of view.
201

202             if (_deleted != null && fkTables != null)
203             {
204                 HashSet JavaDoc intersection = (HashSet JavaDoc) _deleted.clone();
205
206                 intersection.retainAll(fkTables);
207                 if (!intersection.isEmpty())
208                 {
209                     // one of the previous DELETEs contained a table
210
// that is referenced from this table.
211
// Let's execute that previous DELETE right now so that
212
// in the future DELETEs into this table will go first
213
// in the _order array.
214
executeBatch();
215                 }
216             }
217         }
218
219         _order.add(sql);
220
221         _touched.add(tableName);
222         if (sqlCmd.equals("INSERT "))
223         {
224             if (fkTables != null)
225             {
226                 if (_dontInsert == null)
227                 {
228                     _dontInsert = new HashSet JavaDoc();
229                 }
230                 _dontInsert.addAll(fkTables);
231             }
232         }
233         else if (sqlCmd.equals("DELETE "))
234         {
235             if (_deleted == null)
236             {
237                 _deleted = new HashSet JavaDoc();
238             }
239             _deleted.add(tableName);
240         }
241     }
242
243     /**
244      * If UPDATE, INSERT or DELETE, return BatchPreparedStatement,
245      * otherwise return null.
246      */

247     private PreparedStatement JavaDoc prepareBatchStatement(String JavaDoc sql)
248     {
249         String JavaDoc sqlCmd = sql.substring(0, 7);
250
251         if (sqlCmd.equals("UPDATE ") || sqlCmd.equals("DELETE ") || (_useBatchInserts && sqlCmd.equals("INSERT ")))
252         {
253             PreparedStatement JavaDoc stmt = (PreparedStatement JavaDoc) _statements.get(sql);
254             if (stmt == null)
255             {
256                 // [olegnitz] for JDK 1.2 we need to list both PreparedStatement and Statement
257
// interfaces, otherwise proxy.jar works incorrectly
258
stmt = (PreparedStatement JavaDoc) Proxy.newProxyInstance(getClass().getClassLoader(), new Class JavaDoc[]{
259                         PreparedStatement JavaDoc.class, Statement JavaDoc.class, BatchPreparedStatement.class},
260                         new PreparedStatementInvocationHandler(this, sql, m_jcd));
261                 _statements.put(sql, stmt);
262             }
263             return stmt;
264         }
265         else
266         {
267             return null;
268         }
269     }
270
271     public PreparedStatement JavaDoc prepareStatement(String JavaDoc sql) throws SQLException JavaDoc
272     {
273         PreparedStatement JavaDoc stmt = null;
274         stmt = prepareBatchStatement(sql);
275
276         if (stmt == null)
277         {
278             stmt = getDelegate().prepareStatement(sql);
279         }
280         return stmt;
281     }
282
283     public PreparedStatement JavaDoc prepareStatement(String JavaDoc sql, int resultSetType, int resultSetConcurrency)
284             throws SQLException JavaDoc
285     {
286         PreparedStatement JavaDoc stmt = null;
287         stmt = prepareBatchStatement(sql);
288
289         if (stmt == null)
290         {
291             stmt = getDelegate().prepareStatement(sql, resultSetType, resultSetConcurrency);
292         }
293         return stmt;
294     }
295
296     public void executeBatch() throws SQLException JavaDoc
297     {
298         BatchPreparedStatement batchStmt;
299         Connection JavaDoc conn = getDelegate();
300
301         try
302         {
303             for (Iterator JavaDoc it = _order.iterator(); it.hasNext();)
304             {
305                 batchStmt = (BatchPreparedStatement) _statements.get(it.next());
306                 batchStmt.doExecute(conn);
307             }
308         }
309         finally
310         {
311             _order.clear();
312
313             if (_dontInsert != null)
314             {
315                 _dontInsert.clear();
316             }
317
318             if (_deleted != null)
319             {
320                 _deleted.clear();
321             }
322             _touched.clear();
323             count = 0;
324         }
325     }
326
327     public void executeBatchIfNecessary() throws SQLException JavaDoc
328     {
329         if (count >= MAX_COUNT)
330         {
331             executeBatch();
332         }
333     }
334
335     public void clearBatch()
336     {
337         _order.clear();
338         _statements.clear();
339
340         if (_dontInsert != null)
341         {
342             _dontInsert.clear();
343         }
344
345         if (_deleted != null)
346         {
347             _deleted.clear();
348         }
349     }
350
351     public void commit() throws SQLException JavaDoc
352     {
353         executeBatch();
354         _statements.clear();
355         getDelegate().commit();
356     }
357
358     public void rollback() throws SQLException JavaDoc
359     {
360         clearBatch();
361         getDelegate().rollback();
362     }
363 }
Popular Tags