KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > databaseaccess > DatasourceAccessor


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2005, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.databaseaccess;
23
24 import java.util.*;
25 import oracle.toplink.essentials.exceptions.*;
26 import oracle.toplink.essentials.sessions.Login;
27 import oracle.toplink.essentials.queryframework.Call;
28 import oracle.toplink.essentials.logging.SessionLog;
29 import oracle.toplink.essentials.sessions.SessionProfiler;
30 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
31 import oracle.toplink.essentials.internal.sessions.AbstractSession;
32
33 /**
34  * INTERNAL:
35  * <code>DatasourceAccessor</code> is an abstract implementation
36  * of the <code>Accessor</code> interface providing common functionality to the concrete database and EIS accessors.
37  * It is responsible for
38  * connecting,
39  * transactions,
40  * call execution
41  *
42  * @see Call
43  * @see Login
44  *
45  * @author James
46  * @since OracleAS TopLink 10<i>g</i> (10.0.3)
47  */

48 public abstract class DatasourceAccessor implements Accessor {
49
50     /** Store the reference to the driver level connection. */
51     protected Object JavaDoc datasourceConnection;
52
53     /** Store the login information that connected this accessor. */
54     protected Login login;
55
56     /**
57      * Keep track of the number of concurrent active calls.
58      * This is used for connection pooling for loadbalancing and for external connection pooling.
59      */

60     protected int callCount;
61
62     /** Keep track if the accessor is within a transaction context */
63     protected boolean isInTransaction;
64
65     /** Keep track of whether the accessor is "connected". */
66     protected boolean isConnected;
67
68     /** PERF: Cache platform to avoid gets (small but can add up). */
69     /** This is also required to ensure all accessors for a session are using the same platform. */
70     protected DatasourcePlatform platform;
71
72     /**
73      * Default Constructor.
74      */

75     public DatasourceAccessor() {
76         this.isInTransaction = false;
77         this.callCount = 0;
78         this.isConnected = false;
79     }
80
81     /**
82      * Clone the accessor.
83      */

84     public Object JavaDoc clone() {
85         try {
86             DatasourceAccessor accessor = (DatasourceAccessor)super.clone();
87             return accessor;
88         } catch (CloneNotSupportedException JavaDoc exception) {
89             throw new InternalError JavaDoc("clone not supported");
90         }
91     }
92
93     /**
94      * To be called after JTS transaction has been completed (committed or rolled back)
95      */

96     public void afterJTSTransaction() {
97         if (usesExternalTransactionController()) {
98             setIsInTransaction(false);
99             if ((getDatasourceConnection() != null) && usesExternalConnectionPooling()) {
100                 closeConnection();
101                 setDatasourceConnection(null);
102             }
103         }
104     }
105
106     /**
107      * Set the transaction transaction status of the receiver.
108      */

109     protected void setIsInTransaction(boolean value) {
110         isInTransaction = value;
111     }
112
113     /**
114      * Return the transaction status of the receiver.
115      */

116     public boolean isInTransaction() {
117         return isInTransaction;
118     }
119
120     /**
121      * Return true if some external connection pool is in use.
122      */

123     public boolean usesExternalConnectionPooling() {
124         if (getLogin() == null) {
125             throw DatabaseException.databaseAccessorNotConnected();
126         }
127         return getLogin().shouldUseExternalConnectionPooling();
128     }
129
130     /**
131      * Begin a transaction on the database. If not using managed transaction begin a local transaction.
132      */

133     public void beginTransaction(AbstractSession session) throws DatabaseException {
134         if (usesExternalTransactionController()) {
135             setIsInTransaction(true);
136             return;
137         }
138
139         session.log(SessionLog.FINER, SessionLog.TRANSACTION, "begin_transaction", (Object JavaDoc[])null, this);
140
141         try {
142             session.startOperationProfile(SessionProfiler.TRANSACTION);
143             incrementCallCount(session);
144             basicBeginTransaction(session);
145             setIsInTransaction(true);
146         } finally {
147             decrementCallCount();
148             session.endOperationProfile(SessionProfiler.TRANSACTION);
149         }
150     }
151
152     /**
153      * Begin the driver level transaction.
154      */

155     protected abstract void basicBeginTransaction(AbstractSession session);
156
157     /**
158      * Commit the driver level transaction.
159      */

160     protected abstract void basicCommitTransaction(AbstractSession session);
161
162     /**
163      * Rollback the driver level transaction.
164      */

165     protected abstract void basicRollbackTransaction(AbstractSession session);
166
167     /**
168      * Used for load balancing and external pooling.
169      */

170     public synchronized void decrementCallCount() {
171         setCallCount(getCallCount() - 1);
172         if (usesExternalConnectionPooling() && (!isInTransaction()) && (getCallCount() == 0)) {
173             try {
174                 closeConnection();
175             } catch (DatabaseException ignore) {
176             }
177             // Don't allow for errors to be masked by disconnect.
178
}
179     }
180
181     /**
182      * Used for load balancing and external pooling.
183      */

184     public synchronized void incrementCallCount(AbstractSession session) {
185         setCallCount(getCallCount() + 1);
186
187         if (getCallCount() == 1) {
188             // If the login is null, then this accessor has never been connected.
189
if (getLogin() == null) {
190                 throw DatabaseException.databaseAccessorNotConnected();
191             }
192
193             // If the connection is no longer connected, it may have timed out.
194
if (getDatasourceConnection() != null) {
195                 if (!isConnected()) {
196                     if (isInTransaction()) {
197                         throw DatabaseException.databaseAccessorNotConnected();
198                     } else {
199                         reconnect(session);
200                     }
201                 }
202             } else {
203                 // If ExternalConnectionPooling is used, the connection can be re-established.
204
if (usesExternalConnectionPooling()) {
205                     reconnect(session);
206                 } else {
207                     throw DatabaseException.databaseAccessorNotConnected();
208                 }
209             }
210         }
211     }
212
213     /**
214      * Connect to the database.
215      * Exceptions are caught and re-thrown as TopLink exceptions.
216      */

217     protected void connect(Login login) throws DatabaseException {
218         setDatasourceConnection(login.connectToDatasource(this));
219         setIsConnected(true);
220     }
221
222     /**
223      * Set whether the accessor has a connection to the "data store".
224      */

225     protected void setIsConnected(boolean isConnected) {
226         this.isConnected = isConnected;
227     }
228
229     /**
230      * Used for load balancing and external pooling.
231      */

232     protected void setCallCount(int callCount) {
233         this.callCount = callCount;
234     }
235
236     /**
237      * Used for load balancing and external pooling.
238      */

239     public int getCallCount() {
240         return callCount;
241     }
242
243     /**
244      * Commit a transaction on the database. If using non-managed transaction commit the local transaction.
245      */

246     public void commitTransaction(AbstractSession session) throws DatabaseException {
247         if (usesExternalTransactionController()) {
248             // if there is no external TX controller, then that means we are currently not synchronized
249
// with a global JTS transaction. In this case, there won't be any 'afterCompletion'
250
// callbacks so we have to release the connection here. It is possible (WLS 5.1) to choose
251
// 'usesExternalTransactionController' on the login, but still acquire a uow that WON'T be
252
// synchronized with a global TX.
253
if (session.getExternalTransactionController() == null) {
254                 setIsInTransaction(false);
255                 if ((getDatasourceConnection() != null) && usesExternalConnectionPooling()) {
256                     closeConnection();
257                     setDatasourceConnection(null);
258                 }
259             }
260             return;
261         }
262
263         session.log(SessionLog.FINER, SessionLog.TRANSACTION, "commit_transaction", (Object JavaDoc[])null, this);
264
265         try {
266             session.startOperationProfile(SessionProfiler.TRANSACTION);
267             incrementCallCount(session);
268             basicCommitTransaction(session);
269
270             // true=="committed"; false=="not jts transactioin"
271
session.afterTransaction(true, false);
272             setIsInTransaction(false);
273         } finally {
274             decrementCallCount();
275             session.endOperationProfile(SessionProfiler.TRANSACTION);
276         }
277     }
278
279     /**
280      * Connect to the datasource. Through using a CCI ConnectionFactory.
281      * Catch exceptions and re-throw as TopLink exceptions.
282      */

283     public void connect(Login login, AbstractSession session) throws DatabaseException {
284         session.startOperationProfile(SessionProfiler.CONNECT);
285         session.incrementProfile(SessionProfiler.TlConnects);
286
287         try {
288             if (session.shouldLog(SessionLog.CONFIG, SessionLog.CONNECTION)) {// Avoid printing if no logging required.
289
session.log(SessionLog.CONFIG, SessionLog.CONNECTION, "connecting", new Object JavaDoc[] { login }, this);
290             }
291             setLogin(login);
292             this.setDatasourcePlatform((DatasourcePlatform)session.getDatasourceLogin().getDatasourcePlatform());
293             try {
294                 connect(login);
295                 setIsInTransaction(false);
296             } catch (RuntimeException JavaDoc exception) {
297                 session.handleSevere(exception);
298             }
299             session.getEventManager().postConnect(this);
300             incrementCallCount(session);
301             try {
302                 buildConnectLog(session);
303             } finally {
304                 decrementCallCount();
305             }
306         } finally {
307             session.endOperationProfile(SessionProfiler.CONNECT);
308         }
309     }
310
311     /**
312      * Close the connection to the driver level datasource.
313      */

314     protected abstract void closeDatasourceConnection();
315
316     /**
317      * Execute the call to driver level datasource.
318      */

319     protected abstract Object JavaDoc basicExecuteCall(Call call, AbstractRecord row, AbstractSession session);
320
321     /**
322      * Build a log string of any driver metadata that can be obtained.
323      */

324     protected abstract void buildConnectLog(AbstractSession session);
325
326     /**
327      * Return the login
328      */

329     public Login getLogin() {
330         return login;
331     }
332
333     /**
334      * SECURE:
335      * set the login
336      */

337     protected void setLogin(Login login) {
338         this.login = login;
339     }
340
341     /**
342      * Disconnect from the datasource.
343      */

344     public void disconnect(AbstractSession session) throws DatabaseException {
345         session.log(SessionLog.CONFIG, SessionLog.CONNECTION, "disconnect", (Object JavaDoc[])null, this);
346
347         if (getDatasourceConnection() == null) {
348             return;
349         }
350         session.incrementProfile(SessionProfiler.TlDisconnects);
351         session.startOperationProfile(SessionProfiler.CONNECT);
352         closeDatasourceConnection();
353         setDatasourceConnection(null);
354         setIsInTransaction(false);
355         session.endOperationProfile(SessionProfiler.CONNECT);
356     }
357
358     /**
359      * Close the accessor's connection.
360      * This is used only for external connection pooling
361      * when it is intended for the connection to be reconnected in the future.
362      */

363     public void closeConnection() {
364         try {
365             if (getDatasourceConnection() != null) {
366                 if (isDatasourceConnected()) {
367                     closeDatasourceConnection();
368                 }
369                 setDatasourceConnection(null);
370             }
371         } catch (DatabaseException exception) {
372             // Ignore
373
setDatasourceConnection(null);
374         }
375     }
376
377     /**
378      * Execute the call.
379      * @return depending of the type either the row count, row or vector of rows.
380      */

381     public Object JavaDoc executeCall(Call call, AbstractRecord translationRow, AbstractSession session) throws DatabaseException {
382         // If the login is null, then this accessor has never been connected.
383
if (getLogin() == null) {
384             throw DatabaseException.databaseAccessorNotConnected();
385         }
386
387         if (session.shouldLog(SessionLog.FINE, SessionLog.SQL)) {// pre-check to improve performance
388
session.log(SessionLog.FINE, SessionLog.SQL, call.getLogString(this), (Object JavaDoc[])null, this, false);
389         }
390
391         Object JavaDoc result = basicExecuteCall(call, translationRow, session);
392
393         return result;
394     }
395
396     /**
397      * PUBLIC:
398      * Reconnect to the database. This can be used if the connection was disconnected or timedout.
399      * This ensures that the security is checked as it is public.
400      * Because the messages can take a long time to build,
401      * pre-check whether messages should be logged.
402      */

403     public void reestablishConnection(AbstractSession session) throws DatabaseException {
404         if (session.shouldLog(SessionLog.CONFIG, SessionLog.CONNECTION)) {// Avoid printing if no logging required.
405
Object JavaDoc[] args = { getLogin() };
406             session.log(SessionLog.CONFIG, SessionLog.CONNECTION, "reconnecting", args, this);
407         }
408         reconnect(session);
409         setIsInTransaction(false);
410         session.getEventManager().postConnect(this);
411     }
412
413     /**
414      * Attempt to save some of the cost associated with getting a fresh connection.
415      * Assume the DatabaseDriver has been cached, if appropriate.
416      * Note: Connections that are participating in transactions will not be refreshd.^M
417      */

418     protected void reconnect(AbstractSession session) throws DatabaseException {
419         session.log(SessionLog.FINEST, SessionLog.CONNECTION, "reconnecting_to_external_connection_pool");
420         session.startOperationProfile(SessionProfiler.CONNECT);
421         connect(getLogin());
422         session.endOperationProfile(SessionProfiler.CONNECT);
423     }
424
425     /**
426      * Return the platform.
427      */

428     public DatasourcePlatform getDatasourcePlatform() {
429         return platform;
430     }
431
432     /**
433      * Set the platform.
434      * This should be set to the session's platform, not the connections
435      * which may not be configured correctly.
436      */

437     public void setDatasourcePlatform(DatasourcePlatform platform) {
438         this.platform = platform;
439     }
440
441     /**
442      * Return the driver level connection.
443      */

444     public Object JavaDoc getDatasourceConnection() {
445         return datasourceConnection;
446     }
447
448     /**
449      * Helper method to return the JDBC connection for DatabaseAccessor.
450      * Was going to deprecate this, but since most clients are JDBC this is useful.
451      */

452     public java.sql.Connection JavaDoc getConnection() {
453         return (java.sql.Connection JavaDoc)getDatasourceConnection();
454     }
455
456     /**
457      * Return column information for the specified
458      * database objects.
459      */

460     public Vector getColumnInfo(String JavaDoc catalog, String JavaDoc schema, String JavaDoc tableName, String JavaDoc columnName, AbstractSession session) throws DatabaseException {
461         return new Vector();
462     }
463
464     /**
465      * Return table information for the specified
466      * database objects.
467      */

468     public Vector getTableInfo(String JavaDoc catalog, String JavaDoc schema, String JavaDoc tableName, String JavaDoc[] types, AbstractSession session) throws DatabaseException {
469         return new Vector();
470     }
471
472     /**
473      * If client requires to manually set connection they can use the connection manager.
474      */

475     protected void setDatasourceConnection(Object JavaDoc connection) {
476         this.datasourceConnection = connection;
477     }
478
479     /**
480      * Rollback the transaction on the datasource. If not using managed transaction rollback the local transaction.
481      */

482     public void rollbackTransaction(AbstractSession session) throws DatabaseException {
483         if (usesExternalTransactionController()) {
484             // if there is no external TX controller, then that means we are currently not synchronized
485
// with a global JTS transaction. In this case, there won't be any 'afterCompletion'
486
// callbacks so we have to release the connection here. It is possible (WLS 5.1) to choose
487
// 'usesExternalTransactionController' on the login, but still acquire a uow that WON'T be
488
// synchronized with a global TX.
489
if (session.getExternalTransactionController() == null) {
490                 setIsInTransaction(false);
491                 if ((getDatasourceConnection() != null) && usesExternalConnectionPooling()) {
492                     closeConnection();
493                     setDatasourceConnection(null);
494                 }
495             }
496             return;
497         }
498
499         session.log(SessionLog.FINER, SessionLog.TRANSACTION, "rollback_transaction", (Object JavaDoc[])null, this);
500
501         try {
502             session.startOperationProfile(SessionProfiler.TRANSACTION);
503             incrementCallCount(session);
504             basicRollbackTransaction(session);
505         } finally {
506             // false=="rolled back"; false=="not jts transactioin"
507
session.afterTransaction(false, false);
508             setIsInTransaction(false);
509             decrementCallCount();
510             session.endOperationProfile(SessionProfiler.TRANSACTION);
511         }
512     }
513
514     /**
515      * Return true if some external transaction service is controlling transactions.
516      */

517     public boolean usesExternalTransactionController() {
518         if (getLogin() == null) {
519             throw DatabaseException.databaseAccessorNotConnected();
520         }
521         return getLogin().shouldUseExternalTransactionController();
522     }
523
524     /**
525      * Return true if the accessor is currently connected to a data source.
526      * Return false otherwise.
527      */

528     public boolean isConnected() {
529         if ((getDatasourceConnection() == null) && (getLogin() == null)) {
530             return false;
531         }
532         if (usesExternalConnectionPooling()) {
533             return true;// As can always reconnect.
534
}
535
536         if (getDatasourceConnection() == null) {
537             return false;
538         }
539
540         return isDatasourceConnected();
541     }
542
543     /**
544      * Return if the driver level connection is connected.
545      */

546     protected abstract boolean isDatasourceConnected();
547
548     /**
549      * Added as a result of Bug 2804663 - satisfy the Accessor interface
550      * implementation.
551      */

552     public void flushSelectCalls(AbstractSession session) {
553         // By default do nothing.
554
}
555
556     /**
557      * This method will be called after a series of writes have been issued to
558      * mark where a particular set of writes has completed. It will be called
559      * from commitTransaction and may be called from writeChanges. Its main
560      * purpose is to ensure that the batched statements have been executed
561      */

562     public void writesCompleted(AbstractSession session) {
563         //this is a no-op in this method as we do not batch on this accessor
564
}
565 }
566
Popular Tags