KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > access > DataNode


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
57 package org.objectstyle.cayenne.access;
58
59 import java.sql.CallableStatement JavaDoc;
60 import java.sql.Connection JavaDoc;
61 import java.sql.ResultSet JavaDoc;
62 import java.sql.SQLException JavaDoc;
63 import java.util.Collection JavaDoc;
64 import java.util.Collections JavaDoc;
65 import java.util.HashMap JavaDoc;
66 import java.util.Iterator JavaDoc;
67 import java.util.Map JavaDoc;
68
69 import javax.sql.DataSource JavaDoc;
70
71 import org.apache.log4j.Level;
72 import org.objectstyle.cayenne.CayenneException;
73 import org.objectstyle.cayenne.CayenneRuntimeException;
74 import org.objectstyle.cayenne.access.jdbc.BatchAction;
75 import org.objectstyle.cayenne.access.jdbc.ProcedureAction;
76 import org.objectstyle.cayenne.access.jdbc.RowDescriptor;
77 import org.objectstyle.cayenne.access.jdbc.SelectAction;
78 import org.objectstyle.cayenne.access.jdbc.UpdateAction;
79 import org.objectstyle.cayenne.access.trans.BatchQueryBuilder;
80 import org.objectstyle.cayenne.conn.PoolManager;
81 import org.objectstyle.cayenne.dba.DbAdapter;
82 import org.objectstyle.cayenne.dba.JdbcAdapter;
83 import org.objectstyle.cayenne.map.AshwoodEntitySorter;
84 import org.objectstyle.cayenne.map.DataMap;
85 import org.objectstyle.cayenne.map.EntityResolver;
86 import org.objectstyle.cayenne.map.EntitySorter;
87 import org.objectstyle.cayenne.query.BatchQuery;
88 import org.objectstyle.cayenne.query.GenericSelectQuery;
89 import org.objectstyle.cayenne.query.ProcedureQuery;
90 import org.objectstyle.cayenne.query.Query;
91 import org.objectstyle.cayenne.query.SelectQuery;
92
93 /**
94  * Describes a single physical data source. This can be a database server, LDAP server,
95  * etc. When the underlying connection layer is based on JDBC, DataNode works as a Cayenne
96  * wrapper of javax.sql.DataSource.
97  * <p>
98  * <i>For more information see <a HREF="../../../../../../userguide/index.html"
99  * target="_top">Cayenne User Guide. </a> </i>
100  * </p>
101  *
102  * @author Andrei Adamchik
103  */

104 public class DataNode implements QueryEngine {
105
106     public static final Class JavaDoc DEFAULT_ADAPTER_CLASS = JdbcAdapter.class;
107
108     protected String JavaDoc name;
109     protected DataSource JavaDoc dataSource;
110     protected DbAdapter adapter;
111     protected String JavaDoc dataSourceLocation;
112     protected String JavaDoc dataSourceFactory;
113     protected EntityResolver entityResolver;
114     protected EntitySorter entitySorter;
115
116     // ====================================================
117
// DataMaps
118
// ====================================================
119
protected Map JavaDoc dataMaps = new HashMap JavaDoc();
120     private Collection JavaDoc dataMapsValuesRef = Collections.unmodifiableCollection(dataMaps
121             .values());
122
123     /**
124      * Creates a new unnamed DataNode.
125      */

126     public DataNode() {
127         this(null);
128     }
129
130     /**
131      * Creates a new DataNode, assigning it a name.
132      */

133     public DataNode(String JavaDoc name) {
134         this.name = name;
135
136         // since 1.2 we always implement entity sorting, regardless of the underlying DB
137
// as the right order is needed for deferred PK propagation (and maybe other
138
// things too?)
139
this.entitySorter = new AshwoodEntitySorter(Collections.EMPTY_LIST);
140     }
141
142     /** Returns node "name" property. */
143     public String JavaDoc getName() {
144         return name;
145     }
146
147     public void setName(String JavaDoc name) {
148         this.name = name;
149     }
150
151     /** Returns a location of DataSource of this node. */
152     public String JavaDoc getDataSourceLocation() {
153         return dataSourceLocation;
154     }
155
156     public void setDataSourceLocation(String JavaDoc dataSourceLocation) {
157         this.dataSourceLocation = dataSourceLocation;
158     }
159
160     /** Returns a name of DataSourceFactory class for this node. */
161     public String JavaDoc getDataSourceFactory() {
162         return dataSourceFactory;
163     }
164
165     public void setDataSourceFactory(String JavaDoc dataSourceFactory) {
166         this.dataSourceFactory = dataSourceFactory;
167     }
168
169     /**
170      * Returns an unmodifiable collection of DataMaps handled by this DataNode.
171      */

172     public Collection JavaDoc getDataMaps() {
173         return dataMapsValuesRef;
174     }
175
176     public void setDataMaps(Collection JavaDoc dataMaps) {
177         Iterator JavaDoc it = dataMaps.iterator();
178         while (it.hasNext()) {
179             DataMap map = (DataMap) it.next();
180             this.dataMaps.put(map.getName(), map);
181         }
182
183         entitySorter.setDataMaps(dataMaps);
184     }
185
186     /**
187      * Adds a DataMap to be handled by this node.
188      */

189     public void addDataMap(DataMap map) {
190         this.dataMaps.put(map.getName(), map);
191
192         entitySorter.setDataMaps(getDataMaps());
193     }
194
195     public void removeDataMap(String JavaDoc mapName) {
196         DataMap map = (DataMap) dataMaps.remove(mapName);
197         if (map != null) {
198             entitySorter.setDataMaps(getDataMaps());
199         }
200     }
201
202     /**
203      * Returns DataSource used by this DataNode to obtain connections.
204      */

205     public DataSource JavaDoc getDataSource() {
206         return dataSource;
207     }
208
209     public void setDataSource(DataSource JavaDoc dataSource) {
210         this.dataSource = dataSource;
211     }
212
213     /**
214      * Returns DbAdapter object. This is a plugin that handles RDBMS vendor-specific
215      * features.
216      */

217     public DbAdapter getAdapter() {
218         return adapter;
219     }
220
221     public void setAdapter(DbAdapter adapter) {
222         this.adapter = adapter;
223     }
224
225     /**
226      * Returns a DataNode that should hanlde queries for all DataMap components.
227      *
228      * @since 1.1
229      */

230     public DataNode lookupDataNode(DataMap dataMap) {
231         // we don't know any better than to return ourselves...
232
return this;
233     }
234
235     /**
236      * Wraps queries in an internal transaction, and executes them via connection obtained
237      * from internal DataSource.
238      */

239     public void performQueries(Collection JavaDoc queries, OperationObserver observer) {
240         Transaction transaction = Transaction.internalTransaction(null);
241         transaction.performQueries(this, queries, observer);
242     }
243
244     /**
245      * Runs queries using Connection obtained from internal DataSource. Once Connection is
246      * obtained internally, it is added to the Transaction that will handle its closing.
247      *
248      * @since 1.1
249      */

250     public void performQueries(
251             Collection JavaDoc queries,
252             OperationObserver resultConsumer,
253             Transaction transaction) {
254
255         Level logLevel = resultConsumer.getLoggingLevel();
256
257         int listSize = queries.size();
258         if (listSize == 0) {
259             return;
260         }
261         QueryLogger.logQueryStart(logLevel, listSize);
262
263         // since 1.1 Transaction object is required
264
if (transaction == null) {
265             throw new CayenneRuntimeException(
266                     "No transaction associated with the queries.");
267         }
268
269         Connection JavaDoc connection = null;
270
271         try {
272             // check for invalid iterated query
273
if (resultConsumer.isIteratedResult() && listSize > 1) {
274                 throw new CayenneException(
275                         "Iterated queries are not allowed in a batch. Batch size: "
276                                 + listSize);
277             }
278
279             // check out connection
280
connection = this.getDataSource().getConnection();
281             transaction.addConnection(connection);
282         }
283         // catch stuff like connection allocation errors, etc...
284
catch (Exception JavaDoc globalEx) {
285             QueryLogger.logQueryError(logLevel, globalEx);
286
287             if (connection != null) {
288                 // rollback failed transaction
289
transaction.setRollbackOnly();
290             }
291
292             resultConsumer.nextGlobalException(globalEx);
293             return;
294         }
295
296         DataNodeQueryAction queryRunner = new DataNodeQueryAction(this, resultConsumer);
297         Iterator JavaDoc it = queries.iterator();
298         while (it.hasNext()) {
299             Query nextQuery = (Query) it.next();
300
301             // catch exceptions for each individual query
302
try {
303                 queryRunner.runQuery(connection, nextQuery);
304             }
305             catch (Exception JavaDoc queryEx) {
306                 QueryLogger.logQueryError(logLevel, queryEx);
307
308                 // notify consumer of the exception,
309
// stop running further queries
310
resultConsumer.nextQueryException(nextQuery, queryEx);
311
312                 // rollback transaction
313
transaction.setRollbackOnly();
314                 break;
315             }
316         }
317     }
318
319     /**
320      * Executes a SelectQuery.
321      *
322      * @deprecated since 1.2
323      */

324     protected void runSelect(
325             Connection JavaDoc connection,
326             Query query,
327             OperationObserver observer) throws SQLException JavaDoc, Exception JavaDoc {
328
329         new SelectAction((SelectQuery) query, getAdapter(), getEntityResolver())
330                 .performAction(connection, observer);
331     }
332
333     /**
334      * Executes a non-batched updating query.
335      *
336      * @deprecated since 1.2
337      */

338     protected void runUpdate(Connection JavaDoc con, Query query, OperationObserver delegate)
339             throws SQLException JavaDoc, Exception JavaDoc {
340
341         new UpdateAction(query, getAdapter(), getEntityResolver()).performAction(con,
342                 delegate);
343     }
344
345     /**
346      * Executes a batch updating query.
347      *
348      * @deprecated since 1.2
349      */

350     protected void runBatchUpdate(
351             Connection JavaDoc connection,
352             BatchQuery query,
353             OperationObserver observer) throws SQLException JavaDoc, Exception JavaDoc {
354
355         // check run strategy...
356

357         // optimistic locking is not supported in batches due to JDBC driver limitations
358
boolean useOptimisticLock = query.isUsingOptimisticLocking();
359
360         boolean runningAsBatch = !useOptimisticLock && adapter.supportsBatchUpdates();
361         BatchAction action = new BatchAction(query, getAdapter(), getEntityResolver());
362         action.setBatch(runningAsBatch);
363         action.performAction(connection, observer);
364     }
365
366     /**
367      * Executes batch query using JDBC Statement batching features.
368      *
369      * @deprecated since 1.2 SQLActions are used.
370      */

371     protected void runBatchUpdateAsBatch(
372             Connection JavaDoc con,
373             BatchQuery query,
374             BatchQueryBuilder queryBuilder,
375             OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
376         new TempBatchAction(query, true).runAsBatch(con, queryBuilder, delegate);
377     }
378
379     /**
380      * Executes batch query without using JDBC Statement batching features, running
381      * individual statements in the batch one by one.
382      *
383      * @deprecated since 1.2 SQLActions are used.
384      */

385     protected void runBatchUpdateAsIndividualQueries(
386             Connection JavaDoc con,
387             BatchQuery query,
388             BatchQueryBuilder queryBuilder,
389             OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
390
391         new TempBatchAction(query, false).runAsBatch(con, queryBuilder, delegate);
392     }
393
394     /**
395      * @deprecated since 1.2
396      */

397     protected void runStoredProcedure(
398             Connection JavaDoc con,
399             Query query,
400             OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
401
402         new ProcedureAction((ProcedureQuery) query, getAdapter(), getEntityResolver())
403                 .performAction(con, delegate);
404     }
405
406     /**
407      * Helper method that reads OUT parameters of a CallableStatement.
408      *
409      * @deprecated Since 1.2 this logic is moved to SQLAction.
410      */

411     protected void readStoredProcedureOutParameters(
412             CallableStatement JavaDoc statement,
413             org.objectstyle.cayenne.access.util.ResultDescriptor descriptor,
414             Query query,
415             OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
416
417         // method is deprecated, so keep this ugly piece here as a placeholder
418
new TempProcedureAction((ProcedureQuery) query)
419                 .readProcedureOutParameters(statement, delegate);
420     }
421
422     /**
423      * Helper method that reads a ResultSet.
424      *
425      * @deprecated Since 1.2 this logic is moved to SQLAction.
426      */

427     protected void readResultSet(
428             ResultSet JavaDoc resultSet,
429             org.objectstyle.cayenne.access.util.ResultDescriptor descriptor,
430             GenericSelectQuery query,
431             OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
432
433         // method is deprecated, so keep this ugly piece here as a placeholder
434
RowDescriptor rowDescriptor = new RowDescriptor(resultSet, getAdapter()
435                 .getExtendedTypes());
436         new TempProcedureAction((ProcedureQuery) query).readResultSet(resultSet,
437                 rowDescriptor,
438                 query,
439                 delegate);
440     }
441
442     /**
443      * Returns EntityResolver that handles DataMaps of this node.
444      */

445     public EntityResolver getEntityResolver() {
446         return entityResolver;
447     }
448
449     /**
450      * Sets EntityResolver. DataNode relies on externally set EntityResolver, so if the
451      * node is created outside of DataDomain stack, a valid EntityResolver must be
452      * provided explicitly.
453      *
454      * @since 1.1
455      */

456     public void setEntityResolver(
457             org.objectstyle.cayenne.map.EntityResolver entityResolver) {
458         this.entityResolver = entityResolver;
459     }
460
461     /**
462      * Returns EntitySorter used by the DataNode.
463      */

464     public EntitySorter getEntitySorter() {
465         return entitySorter;
466     }
467
468     /**
469      * Tries to close JDBC connections opened by this node's data source.
470      */

471     public synchronized void shutdown() {
472         DataSource JavaDoc ds = getDataSource();
473         try {
474             // TODO: theoretically someone maybe using our PoolManager as a container
475
// mapped DataSource, so we should use some other logic to determine whether
476
// this is a DataNode-managed DS.
477
if (ds instanceof PoolManager) {
478                 ((PoolManager) ds).dispose();
479             }
480         }
481         catch (SQLException JavaDoc ex) {
482         }
483     }
484
485     // this class exists to provide deprecated DataNode methods with access to
486
// various SQLAction implementations. It will be removed once corresponding
487
// DataNode methods are removed
488
final class TempProcedureAction extends ProcedureAction {
489
490         public TempProcedureAction(ProcedureQuery query) {
491             super(query, DataNode.this.adapter, DataNode.this.entityResolver);
492         }
493
494         // changing access to public
495
public void readProcedureOutParameters(
496                 CallableStatement JavaDoc statement,
497                 OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
498             super.readProcedureOutParameters(statement, delegate);
499         }
500
501         // changing access to public
502
public void readResultSet(
503                 ResultSet JavaDoc resultSet,
504                 RowDescriptor descriptor,
505                 GenericSelectQuery query,
506                 OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
507             super.readResultSet(resultSet, descriptor, query, delegate);
508         }
509     }
510
511     // this class exists to provide deprecated DataNode methods with access to
512
// various SQLAction implementations. It will be removed once corresponding
513
// DataNode methods are removed
514
final class TempBatchAction extends BatchAction {
515
516         public TempBatchAction(BatchQuery batchQuery, boolean runningAsBatch) {
517             super(batchQuery, DataNode.this.adapter, DataNode.this.entityResolver);
518             setBatch(runningAsBatch);
519         }
520
521         // making public to access from DataNode
522
protected void runAsBatch(
523                 Connection JavaDoc con,
524                 BatchQueryBuilder queryBuilder,
525                 OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
526             super.runAsBatch(con, queryBuilder, delegate);
527         }
528
529         // making public to access from DataNode
530
public void runAsIndividualQueries(
531                 Connection JavaDoc con,
532                 BatchQueryBuilder queryBuilder,
533                 OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
534             super.runAsIndividualQueries(con, queryBuilder, delegate, false);
535         }
536     }
537
538 }
Popular Tags