KickJava   Java API By Example, From Geeks To Geeks.

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


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

19
20 package org.apache.cayenne.access;
21
22 import java.io.PrintWriter JavaDoc;
23 import java.sql.Connection JavaDoc;
24 import java.sql.SQLException JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Map JavaDoc;
30
31 import javax.sql.DataSource JavaDoc;
32
33 import org.apache.cayenne.CayenneRuntimeException;
34 import org.apache.cayenne.conn.PoolManager;
35 import org.apache.cayenne.dba.DbAdapter;
36 import org.apache.cayenne.map.AshwoodEntitySorter;
37 import org.apache.cayenne.map.DataMap;
38 import org.apache.cayenne.map.EntityResolver;
39 import org.apache.cayenne.map.EntitySorter;
40 import org.apache.cayenne.query.Query;
41
42 /**
43  * Describes a single physical data source. This can be a database server, LDAP server,
44  * etc.
45  * <p>
46  * <i>For more information see <a HREF="../../../../../../userguide/index.html"
47  * target="_top">Cayenne User Guide. </a> </i>
48  * </p>
49  *
50  * @author Andrus Adamchik
51  */

52 public class DataNode implements QueryEngine {
53
54     protected String JavaDoc name;
55     protected DataSource JavaDoc dataSource;
56     protected DbAdapter adapter;
57     protected String JavaDoc dataSourceLocation;
58     protected String JavaDoc dataSourceFactory;
59     protected EntityResolver entityResolver;
60     protected EntitySorter entitySorter;
61     protected Map JavaDoc dataMaps;
62
63     TransactionDataSource readThroughDataSource;
64
65     /**
66      * Creates a new unnamed DataNode.
67      */

68     public DataNode() {
69         this(null);
70     }
71
72     /**
73      * Creates a new DataNode, assigning it a name.
74      */

75     public DataNode(String JavaDoc name) {
76         this.name = name;
77         this.dataMaps = new HashMap JavaDoc();
78         this.readThroughDataSource = new TransactionDataSource();
79
80         // since 1.2 we always implement entity sorting, regardless of the underlying DB
81
// as the right order is needed for deferred PK propagation (and maybe other
82
// things too?)
83
this.entitySorter = new AshwoodEntitySorter(Collections.EMPTY_LIST);
84     }
85
86     /**
87      * Returns node name. Name is used to uniquely identify DataNode within a DataDomain.
88      */

89     public String JavaDoc getName() {
90         return name;
91     }
92
93     public void setName(String JavaDoc name) {
94         this.name = name;
95     }
96
97     /**
98      * Returns a location of DataSource of this node. Depending on how this node was
99      * created, location is either a JNDI name, or a location of node XML file, etc.
100      */

101     public String JavaDoc getDataSourceLocation() {
102         return dataSourceLocation;
103     }
104
105     public void setDataSourceLocation(String JavaDoc dataSourceLocation) {
106         this.dataSourceLocation = dataSourceLocation;
107     }
108
109     /**
110      * Returns a name of DataSourceFactory class for this node.
111      */

112     public String JavaDoc getDataSourceFactory() {
113         return dataSourceFactory;
114     }
115
116     public void setDataSourceFactory(String JavaDoc dataSourceFactory) {
117         this.dataSourceFactory = dataSourceFactory;
118     }
119
120     /**
121      * Returns an unmodifiable collection of DataMaps handled by this DataNode.
122      */

123     public Collection JavaDoc getDataMaps() {
124         return Collections.unmodifiableCollection(dataMaps.values());
125     }
126
127     public void setDataMaps(Collection JavaDoc dataMaps) {
128         Iterator JavaDoc it = dataMaps.iterator();
129         while (it.hasNext()) {
130             DataMap map = (DataMap) it.next();
131             this.dataMaps.put(map.getName(), map);
132         }
133
134         entitySorter.setDataMaps(dataMaps);
135     }
136
137     /**
138      * Adds a DataMap to be handled by this node.
139      */

140     public void addDataMap(DataMap map) {
141         this.dataMaps.put(map.getName(), map);
142
143         entitySorter.setDataMaps(getDataMaps());
144     }
145
146     public void removeDataMap(String JavaDoc mapName) {
147         DataMap map = (DataMap) dataMaps.remove(mapName);
148         if (map != null) {
149             entitySorter.setDataMaps(getDataMaps());
150         }
151     }
152
153     /**
154      * Returns DataSource used by this DataNode to obtain connections.
155      */

156     public DataSource JavaDoc getDataSource() {
157         return dataSource != null ? readThroughDataSource : null;
158     }
159
160     public void setDataSource(DataSource JavaDoc dataSource) {
161         this.dataSource = dataSource;
162     }
163
164     /**
165      * Returns DbAdapter object. This is a plugin that handles RDBMS vendor-specific
166      * features.
167      */

168     public DbAdapter getAdapter() {
169         return adapter;
170     }
171
172     public void setAdapter(DbAdapter adapter) {
173         this.adapter = adapter;
174     }
175
176     /**
177      * Returns a DataNode that should hanlde queries for all DataMap components.
178      *
179      * @since 1.1
180      */

181     public DataNode lookupDataNode(DataMap dataMap) {
182         // we don't know any better than to return ourselves...
183
return this;
184     }
185
186     /**
187      * Runs queries using Connection obtained from internal DataSource.
188      *
189      * @since 1.1
190      */

191     public void performQueries(Collection JavaDoc queries, OperationObserver callback) {
192
193         int listSize = queries.size();
194         if (listSize == 0) {
195             return;
196         }
197
198         if (callback.isIteratedResult() && listSize > 1) {
199             throw new CayenneRuntimeException(
200                     "Iterated queries are not allowed in a batch. Batch size: "
201                             + listSize);
202         }
203
204         QueryLogger.logQueryStart(listSize);
205
206         // do this meaningless inexpensive operation to trigger AutoAdapter lazy
207
// initialization before opening a connection. Otherwise we may end up with two
208
// connections open simultaneously, possibly hitting connection pool upper limit.
209
getAdapter().getExtendedTypes();
210
211         Connection JavaDoc connection = null;
212
213         try {
214             connection = this.getDataSource().getConnection();
215         }
216         catch (Exception JavaDoc globalEx) {
217             QueryLogger.logQueryError(globalEx);
218
219             Transaction transaction = Transaction.getThreadTransaction();
220             if (transaction != null) {
221                 transaction.setRollbackOnly();
222             }
223
224             callback.nextGlobalException(globalEx);
225             return;
226         }
227
228         try {
229             DataNodeQueryAction queryRunner = new DataNodeQueryAction(this, callback);
230             Iterator JavaDoc it = queries.iterator();
231             while (it.hasNext()) {
232                 Query nextQuery = (Query) it.next();
233
234                 // catch exceptions for each individual query
235
try {
236                     queryRunner.runQuery(connection, nextQuery);
237                 }
238                 catch (Exception JavaDoc queryEx) {
239                     QueryLogger.logQueryError(queryEx);
240
241                     // notify consumer of the exception,
242
// stop running further queries
243
callback.nextQueryException(nextQuery, queryEx);
244
245                     Transaction transaction = Transaction.getThreadTransaction();
246                     if (transaction != null) {
247                         transaction.setRollbackOnly();
248                     }
249                     break;
250                 }
251             }
252         }
253         finally {
254             try {
255                 connection.close();
256             }
257             catch (SQLException JavaDoc e) {
258                 // ignore closing exceptions...
259
}
260         }
261     }
262
263     /**
264      * Returns EntityResolver that handles DataMaps of this node.
265      */

266     public EntityResolver getEntityResolver() {
267         return entityResolver;
268     }
269
270     /**
271      * Sets EntityResolver. DataNode relies on externally set EntityResolver, so if the
272      * node is created outside of DataDomain stack, a valid EntityResolver must be
273      * provided explicitly.
274      *
275      * @since 1.1
276      */

277     public void setEntityResolver(org.apache.cayenne.map.EntityResolver entityResolver) {
278         this.entityResolver = entityResolver;
279     }
280
281     /**
282      * Returns EntitySorter used by the DataNode.
283      */

284     public EntitySorter getEntitySorter() {
285         return entitySorter;
286     }
287
288     /**
289      * Sets an EntitySorter that is used to order objects on commit.
290      *
291      * @since 1.2
292      */

293     public void setEntitySorter(EntitySorter entitySorter) {
294         this.entitySorter = entitySorter;
295     }
296
297     /**
298      * Tries to close JDBC connections opened by this node's data source.
299      */

300     public synchronized void shutdown() {
301         try {
302             // TODO: theoretically someone maybe using our PoolManager as a container
303
// mapped DataSource, so we should use some other logic to determine whether
304
// this is a DataNode-managed DS.
305
if (dataSource instanceof PoolManager) {
306                 ((PoolManager) dataSource).dispose();
307                 dataSource = null;
308             }
309         }
310         catch (SQLException JavaDoc ex) {
311         }
312     }
313
314     // a read-through DataSource that ensures returning the same connection within
315
// transaction.
316
final class TransactionDataSource implements DataSource JavaDoc {
317
318         final String JavaDoc CONNECTION_RESOURCE_PREFIX = "DataNode.Connection.";
319
320         public Connection JavaDoc getConnection() throws SQLException JavaDoc {
321             Transaction t = Transaction.getThreadTransaction();
322             if (t != null) {
323                 String JavaDoc key = CONNECTION_RESOURCE_PREFIX + name;
324                 Connection JavaDoc c = t.getConnection(key);
325
326                 if (c == null || c.isClosed()) {
327                     c = dataSource.getConnection();
328                     t.addConnection(key, c);
329                 }
330
331                 // wrap transaction-attached connections in a decorator that prevents them
332
// from being closed by callers, as transaction should take care of them
333
// on commit or rollback.
334
return new TransactionConnectionDecorator(c);
335             }
336
337             return dataSource.getConnection();
338         }
339
340         public Connection JavaDoc getConnection(String JavaDoc username, String JavaDoc password)
341                 throws SQLException JavaDoc {
342
343             Transaction t = Transaction.getThreadTransaction();
344             if (t != null) {
345                 String JavaDoc key = CONNECTION_RESOURCE_PREFIX + name;
346                 Connection JavaDoc c = t.getConnection(key);
347
348                 if (c == null || c.isClosed()) {
349                     c = dataSource.getConnection();
350                     t.addConnection(key, c);
351                 }
352
353                 // wrap transaction-attached connections in a decorator that prevents them
354
// from being closed by callers, as transaction should take care of them
355
// on commit or rollback.
356
return new TransactionConnectionDecorator(c);
357             }
358
359             return dataSource.getConnection(username, password);
360         }
361
362         public int getLoginTimeout() throws SQLException JavaDoc {
363             return dataSource.getLoginTimeout();
364         }
365
366         public PrintWriter JavaDoc getLogWriter() throws SQLException JavaDoc {
367             return dataSource.getLogWriter();
368         }
369
370         public void setLoginTimeout(int seconds) throws SQLException JavaDoc {
371             dataSource.setLoginTimeout(seconds);
372         }
373
374         public void setLogWriter(PrintWriter JavaDoc out) throws SQLException JavaDoc {
375             dataSource.setLogWriter(out);
376         }
377     }
378 }
379
Popular Tags