KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > threetier > ClientSession


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.threetier;
23
24 import java.util.*;
25 import java.io.*;
26 import oracle.toplink.essentials.platform.server.ServerPlatform;
27 import oracle.toplink.essentials.queryframework.*;
28 import oracle.toplink.essentials.exceptions.*;
29 import oracle.toplink.essentials.internal.databaseaccess.*;
30 import oracle.toplink.essentials.internal.sequencing.Sequencing;
31 import oracle.toplink.essentials.internal.sequencing.SequencingFactory;
32 import oracle.toplink.essentials.logging.SessionLog;
33 import oracle.toplink.essentials.internal.sessions.*;
34 import oracle.toplink.essentials.sessions.Project;
35 import oracle.toplink.essentials.sessions.SessionProfiler;
36 import oracle.toplink.essentials.internal.sessions.AbstractSession;
37
38 /**
39  * <b>Purpose</b>: Acts as a client to the server session.
40  * <p>
41  * <b>Description</b>: This session is brokered by the server session for use in three-tiered applications.
42  * It is used to store the context of the connection, i.e. the login to be used for this cleint.
43  * This allows each client connected to the server to contain its own user login.
44  * <p>
45  * <b>Responsibilities</b>:
46  * <ul>
47  * <li> Allow units of work to be acquired and pass them the client login's exclusive connection.
48  * <li> Forward all requests and queries to its parent server session.
49  * </ul>
50  * <p>
51  * This class is an implementation of {@link oracle.toplink.essentials.sessions.Session}.
52  * Please refer to that class for a full API. The public interface should be used.
53  * @see Server
54  * @see oracle.toplink.essentials.sessions.UnitOfWork
55  */

56 public class ClientSession extends AbstractSession {
57     protected ServerSession parent;
58     protected ConnectionPolicy connectionPolicy;
59     protected Accessor writeConnection;
60     protected boolean isActive;
61     protected Sequencing sequencing;
62
63     /**
64      * INTERNAL:
65      * Create and return a new client session.
66      */

67     public ClientSession(ServerSession parent, ConnectionPolicy connectionPolicy) {
68         super(parent.getProject());
69         if (connectionPolicy.isUserDefinedConnection()) {
70             // PERF: project only requires clone if login is different
71
this.setProject((Project)getProject().clone());
72             this.setLogin(connectionPolicy.getLogin());
73         }
74         this.isActive = true;
75         this.externalTransactionController = parent.getExternalTransactionController();
76         this.parent = parent;
77         this.connectionPolicy = connectionPolicy;
78         this.writeConnection = this.accessor; // Uses accessor as write unless is pooled.
79
this.accessor = parent.getAccessor(); // This is used for reading only.
80
this.name = parent.getName();
81         this.profiler = parent.getProfiler();
82         this.isInProfile = parent.isInProfile;
83         this.commitManager = parent.getCommitManager();
84         this.sessionLog = parent.getSessionLog();
85         this.eventManager = parent.getEventManager().clone(this);
86         this.exceptionHandler = parent.getExceptionHandler();
87
88         getEventManager().postAcquireClientSession();
89         incrementProfile(SessionProfiler.ClientSessionCreated);
90     }
91
92     protected ClientSession(oracle.toplink.essentials.sessions.Project project) {
93         super(project);
94     }
95
96     /**
97      * INTERNAL:
98      * Called after transaction is completed (committed or rolled back)
99      */

100     public void afterTransaction(boolean committed, boolean isExternalTransaction) {
101         if (hasWriteConnection()) {
102             getParent().afterTransaction(committed, isExternalTransaction, getWriteConnection());
103             if (isExternalTransaction) {
104                 getWriteConnection().afterJTSTransaction();
105                 releaseWriteConnection();
106             }
107         }
108     }
109
110     /**
111      * INTERNAL:
112      * This is internal to the unit of work and should never be called otherwise.
113      */

114     public void basicBeginTransaction() {
115         // if an exclusve connection is use this client session may have
116
// a connection already
117
if (!hasWriteConnection()) {
118             // Ensure that the client is logged in for lazy clients.
119
if (getConnectionPolicy().isLazy()) {
120                 getParent().acquireClientConnection(this);
121             }
122         }
123         super.basicBeginTransaction();
124     }
125
126     /**
127      * INTERNAL:
128      * This is internal to the unit of work and should not be called otherwise.
129      */

130     public void basicCommitTransaction() {
131         //Only releasee connection when transaction succeeds.
132
//If not, connection will be released in rollback.
133
super.basicCommitTransaction();
134
135         // the connection will be released by afterCompletion callback to
136
// afterTransaction(., true);
137
if (!getParent().getDatasourceLogin().shouldUseExternalTransactionController()) {
138             releaseWriteConnection();
139         }
140         // if there is no external TX controller, then that means we are currently not synchronized
141
// with a global JTS transaction. In this case, there won't be any 'afterCompletion'
142
// callbacks so we have to release the connection here. It is possible (WLS 5.1) to choose
143
// 'usesExternalTransactionController' on the login, but still acquire a uow that WON'T be
144
// synchronized with a global TX.
145
else if (this.getExternalTransactionController() == null) {
146             releaseWriteConnection();
147         }
148     }
149
150     /**
151      * INTERNAL:
152      * This is internal to the unit of work and should not be called otherwise.
153      */

154     public void basicRollbackTransaction() {
155         try {
156             //BUG 2660471: Make sure there is an accessor (moved here from Session)
157
//BUG 2846785: EXCEPTION THROWN IN PREBEGINTRANSACTION EVENT CAUSES NPE
158
if (hasWriteConnection()) {
159                 super.basicRollbackTransaction();
160             }
161         } finally {
162             // the connection will be released by afterCompletion callback to
163
// afterTransaction(., true);
164
if (!getParent().getDatasourceLogin().shouldUseExternalTransactionController()) {
165                 releaseWriteConnection();
166             }
167             // if there is no external TX controller, then that means we are currently not synchronized
168
// with a global JTS transaction. In this case, there won't be any 'afterCompletion'
169
// callbacks so we have to release the connection here. It is possible (WLS 5.1) to choose
170
// 'usesExternalTransactionController' on the login, but still acquire a uow that WON'T be
171
// synchronized with a global TX.
172
else if (this.getExternalTransactionController() == null) {
173                 releaseWriteConnection();
174             }
175         }
176     }
177
178     /**
179      * INTERNAL:
180      * Connect the session only (this must be the write connection as the read is shared).
181      */

182     public void connect() throws DatabaseException {
183         getWriteConnection().connect(getDatasourceLogin(), this);
184     }
185
186     /**
187      * INTERNAL:
188      * Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}.
189      * Return true if the pre-defined query is defined on the session.
190      */

191     public boolean containsQuery(String JavaDoc queryName) {
192         boolean containsQuery = getQueries().containsKey(queryName);
193         if (containsQuery == false) {
194             containsQuery = getParent().containsQuery(queryName);
195         }
196         return containsQuery;
197     }
198
199     /**
200      * INTERNAL:
201      * Disconnect the accessor only (this must be the write connection as the read is shared).
202      */

203     public void disconnect() throws DatabaseException {
204         getWriteConnection().disconnect(this);
205     }
206
207     /**
208      * INTERNAL:
209      * Release in case not released.
210      */

211     protected void finalize() throws DatabaseException {
212         if (isActive()) {
213             release();
214         }
215     }
216
217     /**
218      * INTERNAL:
219      * Return the read or write connection depending on the transaction state.
220      */

221     public Accessor getAccessor() {
222         if (isInTransaction()) {
223             return getWriteConnection();
224         }
225         return super.getAccessor();
226     }
227
228     /**
229      * ADVANCED:
230      * This method will return the connection policy that was used during the
231      * acquisition of this client session. The properties within the ConnectionPolicy
232      * may be used when acquiring an exclusive connection for an IsolatedSession.
233      */

234     public ConnectionPolicy getConnectionPolicy() {
235         return connectionPolicy;
236     }
237
238     /**
239      * INTERNAL:
240      * Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}.
241      * Return all registered descriptors.
242      * The clients session inherits its parent's descriptors.
243      */

244     public Map getDescriptors() {
245         return getParent().getDescriptors();
246     }
247
248     /**
249      * INTERNAL:
250      * Gets the next link in the chain of sessions followed by a query's check
251      * early return, the chain of sessions with identity maps all the way up to
252      * the root session.
253      * <p>
254      * Used for session broker which delegates to registered sessions, or UnitOfWork
255      * which checks parent identity map also.
256      * @param canReturnSelf true when method calls itself. If the path
257      * starting at <code>this</code> is acceptable. Sometimes true if want to
258      * move to the first valid session, i.e. executing on ClientSession when really
259      * should be on ServerSession.
260      * @param terminalOnly return the session we will execute the call on, not
261      * the next step towards it.
262      * @return this if there is no next link in the chain
263      */

264     public AbstractSession getParentIdentityMapSession(DatabaseQuery query, boolean canReturnSelf, boolean terminalOnly) {
265         // Note could return self as ClientSession shares the same identity map
266
// as parent. This reveals a deep problem, as queries will be cached in
267
// the Server identity map but executed here using the write connection.
268
return getParent().getParentIdentityMapSession(query, canReturnSelf, terminalOnly);
269     }
270
271     /**
272      * INTERNAL:
273      * Gets the session which this query will be executed on.
274      * Generally will be called immediately before the call is translated,
275      * which is immediately before session.executeCall.
276      * <p>
277      * Since the execution session also knows the correct datasource platform
278      * to execute on, it is often used in the mappings where the platform is
279      * needed for type conversion, or where calls are translated.
280      * <p>
281      * Is also the session with the accessor. Will return a ClientSession if
282      * it is in transaction and has a write connection.
283      * @return a session with a live accessor
284      * @param query may store session name or reference class for brokers case
285      */

286     public AbstractSession getExecutionSession(DatabaseQuery query) {
287         // For CR#4334 if in transaction stay on client session.
288
// That way client's write accessor will be used for all queries.
289
// This is to preserve transaction isolation levels.
290
// For bug 3602222 if a query is executed directly on a client session when
291
// in transaction, then dirty data could be put in the shared cache for the
292
// client session uses the identity map of its parent.
293
// However beginTransaction() is not public API on ClientSession.
294
// if fix this could add: && (query.getSession() != this).
295
if (isInTransaction()) {
296             return this;
297         }
298         return getParent().getExecutionSession(query);
299     }
300
301     /**
302      * INTERNAL:
303      * Return the parent.
304      * This is a server session.
305      */

306     public ServerSession getParent() {
307         return parent;
308     }
309
310     /**
311      * INTERNAL:
312      * Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}.
313      * Return the query from the session pre-defined queries with the given name.
314      * This allows for common queries to be pre-defined, reused and executed by name.
315      */

316     public DatabaseQuery getQuery(String JavaDoc name) {
317         DatabaseQuery query = (DatabaseQuery)super.getQuery(name);
318         if (query == null) {
319             query = getParent().getQuery(name);
320         }
321
322         return query;
323     }
324
325     /**
326      * INTERNAL:
327      */

328     public DatabaseQuery getQuery(String JavaDoc name, Vector args) {// CR3716; Predrag;
329
DatabaseQuery query = super.getQuery(name, args);
330         if (query == null) {
331             query = getParent().getQuery(name, args);
332         }
333         return query;
334     }
335
336     /**
337     * INTERNAL:
338     * was ADVANCED:
339     * Creates sequencing object for the session.
340     * Typically there is no need for the user to call this method -
341     * it is called from the constructor.
342     */

343     public void initializeSequencing() {
344         this.sequencing = SequencingFactory.createSequencing(this);
345     }
346
347     /**
348     * INTERNAL:
349     * Return the Sequencing object used by the session.
350     * Lazy init sequencing to defer from client session creation to improve creation performance.
351     */

352     public Sequencing getSequencing() {
353         // PERF: lazy init defer from constructor, only created when needed.
354
if (sequencing == null) {
355             initializeSequencing();
356         }
357         return sequencing;
358     }
359
360     /**
361      * INTERNAL:
362      * Marked internal as this is not customer API but helper methods for
363      * accessing the server platform from within TopLink's other sessions types
364      * (ie not DatabaseSession)
365      */

366     public ServerPlatform getServerPlatform(){
367         return getParent().getServerPlatform();
368     }
369
370     /**
371      * INTERNAL:
372      * Returns the type of session, its class.
373      * <p>
374      * Override to hide from the user when they are using an internal subclass
375      * of a known class.
376      * <p>
377      * A user does not need to know that their UnitOfWork is a
378      * non-deferred UnitOfWork, or that their ClientSession is an
379      * IsolatedClientSession.
380      */

381     public String JavaDoc getSessionTypeString() {
382         return "ClientSession";
383     }
384
385     /**
386      * INTERNAL:
387      * Return the connection to be used for database modification.
388      */

389     public Accessor getWriteConnection() {
390         return writeConnection;
391     }
392
393     /**
394      * INTERNAL:
395      * Return if this session has been connected.
396      */

397     protected boolean hasWriteConnection() {
398         if (getWriteConnection() == null) {
399             return false;
400         }
401
402         return getWriteConnection().isConnected();
403     }
404
405     /**
406      * INTERNAL:
407      * Set up the IdentityMapManager. This method allows subclasses of Session to override
408      * the default IdentityMapManager functionality.
409      */

410     public void initializeIdentityMapAccessor() {
411         this.identityMapAccessor = new ClientSessionIdentityMapAccessor(this);
412     }
413
414     /**
415      * INTERNAL:
416      * Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}.
417      * Return if the client session is actvie (has not been released).
418      */

419     public boolean isActive() {
420         return isActive;
421     }
422
423     /**
424      * INTERNAL:
425      * Return if this session is a client session.
426      */

427     public boolean isClientSession() {
428         return true;
429     }
430
431     /**
432      * INTERNAL:
433      * Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}.
434      * Return if this session has been connected to the database.
435      */

436     public boolean isConnected() {
437         return getParent().isConnected();
438     }
439
440     /**
441      * INTERNAL:
442      * Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}.
443      * Release the client session.
444      * This releases the client session back to it server.
445      * Normally this will logout of the client session's connection,
446      * and allow the client session to garbage collect.
447      */

448     public void release() throws DatabaseException {
449         if (!isActive()) {
450             return;
451         }
452         getEventManager().preReleaseClientSession();
453
454         //removed is Lazy check as we should always release the connection once
455
//the client session has been released. It is also required for the
456
//behaviour of a subclass ExclusiveIsolatedClientSession
457
if (hasWriteConnection()) {
458             getParent().releaseClientSession(this);
459         }
460
461         // we are not inactive until the connection is released
462
setIsActive(false);
463         log(SessionLog.FINER, SessionLog.CONNECTION, "client_released");
464         getEventManager().postReleaseClientSession();
465     }
466
467     /**
468      * INTERNAL:
469      * This is internal to the unit of work and should not be called otherwise.
470      */

471     protected void releaseWriteConnection() {
472         if (getConnectionPolicy().isLazy() && hasWriteConnection()) {
473             getParent().releaseClientSession(this);
474             setWriteConnection(null);
475         }
476     }
477
478     /**
479      * INTERNAL:
480      * Set the connection policy.
481      */

482     protected void setConnectionPolicy(ConnectionPolicy connectionPolicy) {
483         this.connectionPolicy = connectionPolicy;
484     }
485
486     /**
487      * INTERNAL:
488      * Set if the client session is actvie (has not been released).
489      */

490     protected void setIsActive(boolean isActive) {
491         this.isActive = isActive;
492     }
493
494     /**
495      * INTERNAL:
496      * Set the parent.
497      * This is a server session.
498      */

499     protected void setParent(ServerSession parent) {
500         this.parent = parent;
501     }
502
503     /**
504      * INTERNAL:
505      * Set the connection to be used for database modification.
506      */

507     public void setWriteConnection(Accessor writeConnection) {
508         this.writeConnection = writeConnection;
509     }
510
511     /**
512      * INTERNAL:
513      * Print the connection status with the session.
514      */

515     public String JavaDoc toString() {
516         StringWriter writer = new StringWriter();
517         writer.write(getSessionTypeString());
518         writer.write("(");
519         writer.write(String.valueOf(getWriteConnection()));
520         writer.write(")");
521         return writer.toString();
522     }
523 }
524
Popular Tags