KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > access > jdbc > BatchAction


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56 package org.objectstyle.cayenne.access.jdbc;
57
58 import java.sql.Connection JavaDoc;
59 import java.sql.PreparedStatement JavaDoc;
60 import java.sql.ResultSet JavaDoc;
61 import java.sql.SQLException JavaDoc;
62 import java.sql.Statement JavaDoc;
63 import java.util.Collections JavaDoc;
64 import java.util.Iterator JavaDoc;
65 import java.util.Map JavaDoc;
66
67 import org.apache.log4j.Level;
68 import org.objectstyle.cayenne.CayenneException;
69 import org.objectstyle.cayenne.access.OperationObserver;
70 import org.objectstyle.cayenne.access.OptimisticLockException;
71 import org.objectstyle.cayenne.access.QueryLogger;
72 import org.objectstyle.cayenne.access.ResultIterator;
73 import org.objectstyle.cayenne.access.trans.BatchQueryBuilder;
74 import org.objectstyle.cayenne.access.trans.DeleteBatchQueryBuilder;
75 import org.objectstyle.cayenne.access.trans.InsertBatchQueryBuilder;
76 import org.objectstyle.cayenne.access.trans.UpdateBatchQueryBuilder;
77 import org.objectstyle.cayenne.dba.DbAdapter;
78 import org.objectstyle.cayenne.map.DbAttribute;
79 import org.objectstyle.cayenne.map.EntityResolver;
80 import org.objectstyle.cayenne.query.BatchQuery;
81 import org.objectstyle.cayenne.query.DeleteBatchQuery;
82 import org.objectstyle.cayenne.query.InsertBatchQuery;
83 import org.objectstyle.cayenne.query.UpdateBatchQuery;
84
85 /**
86  * @since 1.2
87  * @author Andrei Adamchik
88  */

89 public class BatchAction extends BaseSQLAction {
90
91     protected boolean batch;
92     protected BatchQuery query;
93
94     public BatchAction(BatchQuery batchQuery, DbAdapter adapter,
95             EntityResolver entityResolver) {
96         super(adapter, entityResolver);
97         this.query = batchQuery;
98     }
99
100     public boolean isBatch() {
101         return batch;
102     }
103
104     public void setBatch(boolean runningAsBatch) {
105         this.batch = runningAsBatch;
106     }
107
108     public void performAction(Connection JavaDoc connection, OperationObserver observer)
109             throws SQLException JavaDoc, Exception JavaDoc {
110
111         BatchQueryBuilder queryBuilder = createBuilder();
112         boolean generatesKeys = hasGeneratedKeys();
113
114         if (batch && !generatesKeys) {
115             runAsBatch(connection, queryBuilder, observer);
116         }
117         else {
118             runAsIndividualQueries(connection, queryBuilder, observer, generatesKeys);
119         }
120     }
121
122     protected BatchQueryBuilder createBuilder() throws CayenneException {
123         if (query instanceof InsertBatchQuery) {
124             return new InsertBatchQueryBuilder(getAdapter());
125         }
126         else if (query instanceof UpdateBatchQuery) {
127             return new UpdateBatchQueryBuilder(getAdapter());
128         }
129         else if (query instanceof DeleteBatchQuery) {
130             return new DeleteBatchQueryBuilder(getAdapter());
131         }
132         else {
133             throw new CayenneException("Unsupported batch query: " + query);
134         }
135     }
136
137     protected void runAsBatch(
138             Connection JavaDoc con,
139             BatchQueryBuilder queryBuilder,
140             OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
141
142         String JavaDoc queryStr = queryBuilder.createSqlString(query);
143         Level logLevel = query.getLoggingLevel();
144         boolean isLoggable = QueryLogger.isLoggable(logLevel);
145
146         // log batch SQL execution
147
QueryLogger.logQuery(logLevel, queryStr, Collections.EMPTY_LIST);
148
149         // run batch
150
query.reset();
151
152         PreparedStatement JavaDoc statement = con.prepareStatement(queryStr);
153         try {
154             while (query.next()) {
155
156                 if (isLoggable) {
157                     QueryLogger.logQueryParameters(logLevel, "batch bind", queryBuilder
158                             .getParameterValues(query));
159                 }
160
161                 queryBuilder.bindParameters(statement, query);
162                 statement.addBatch();
163             }
164
165             // execute the whole batch
166
int[] results = statement.executeBatch();
167             delegate.nextBatchCount(query, results);
168
169             if (isLoggable) {
170                 QueryLogger.logUpdateCount(logLevel, statement.getUpdateCount());
171             }
172         }
173         finally {
174             try {
175                 statement.close();
176             }
177             catch (Exception JavaDoc e) {
178             }
179         }
180     }
181
182     /**
183      * Executes batch as individual queries over the same prepared statement.
184      */

185     protected void runAsIndividualQueries(
186             Connection JavaDoc connection,
187             BatchQueryBuilder queryBuilder,
188             OperationObserver delegate,
189             boolean generatesKeys) throws SQLException JavaDoc, Exception JavaDoc {
190
191         Level logLevel = query.getLoggingLevel();
192         boolean isLoggable = QueryLogger.isLoggable(logLevel);
193         boolean useOptimisticLock = query.isUsingOptimisticLocking();
194
195         String JavaDoc queryStr = queryBuilder.createSqlString(query);
196
197         // log batch SQL execution
198
QueryLogger.logQuery(logLevel, queryStr, Collections.EMPTY_LIST);
199
200         // run batch queries one by one
201
query.reset();
202
203         PreparedStatement JavaDoc statement = (generatesKeys) ? connection
204                 .prepareStatement(queryStr, Statement.RETURN_GENERATED_KEYS) : connection
205                 .prepareStatement(queryStr);
206         try {
207             while (query.next()) {
208                 if (isLoggable) {
209                     QueryLogger.logQueryParameters(logLevel, "bind", queryBuilder
210                             .getParameterValues(query));
211                 }
212
213                 queryBuilder.bindParameters(statement, query);
214
215                 int updated = statement.executeUpdate();
216                 if (useOptimisticLock && updated != 1) {
217
218                     Map JavaDoc snapshot = Collections.EMPTY_MAP;
219                     if (query instanceof UpdateBatchQuery) {
220                         snapshot = ((UpdateBatchQuery) query).getCurrentQualifier();
221                     }
222                     else if (query instanceof DeleteBatchQuery) {
223                         snapshot = ((DeleteBatchQuery) query).getCurrentQualifier();
224                     }
225
226                     throw new OptimisticLockException(
227                             query.getDbEntity(),
228                             queryStr,
229                             snapshot);
230                 }
231
232                 delegate.nextCount(query, updated);
233
234                 if (generatesKeys) {
235                     processGeneratedKeys(statement, delegate);
236                 }
237
238                 if (isLoggable) {
239                     QueryLogger.logUpdateCount(logLevel, updated);
240                 }
241             }
242         }
243         finally {
244             try {
245                 statement.close();
246             }
247             catch (Exception JavaDoc e) {
248             }
249         }
250     }
251
252     /**
253      * Returns whether BatchQuery generates any keys.
254      */

255     protected boolean hasGeneratedKeys() {
256         // see if we are configured to support generated keys
257
if (!adapter.supportsGeneratedKeys()) {
258             return false;
259         }
260
261         // see if the query needs them
262
if (query instanceof InsertBatchQuery) {
263
264             // see if any of the generated attributes is PK
265
Iterator JavaDoc attributes = query.getDbEntity().getGeneratedAttributes().iterator();
266             while (attributes.hasNext()) {
267                 if (((DbAttribute) attributes.next()).isPrimaryKey()) {
268                     return true;
269                 }
270             }
271         }
272
273         return false;
274     }
275
276     /**
277      * Implements generated keys extraction supported since JDBC 3.0 specification.
278      */

279     protected void processGeneratedKeys(Statement JavaDoc statement, OperationObserver observer)
280             throws SQLException JavaDoc, CayenneException {
281
282         ResultSet JavaDoc keysRS = statement.getGeneratedKeys();
283         RowDescriptor descriptor = new RowDescriptor(keysRS, getAdapter()
284                 .getExtendedTypes());
285         ResultIterator iterator = new JDBCResultIterator(
286                 null,
287                 null,
288                 keysRS,
289                 descriptor,
290                 0);
291
292         observer.nextGeneratedDataRows(query, iterator);
293     }
294 }
Popular Tags