FileDocCategorySizeDatePackage
ClientSession.javaAPI DocGlassfish v2 API20122Tue May 22 16:54:54 BST 2007oracle.toplink.essentials.threetier

ClientSession

public class ClientSession extends oracle.toplink.essentials.internal.sessions.AbstractSession
Purpose: Acts as a client to the server session.

Description: This session is brokered by the server session for use in three-tiered applications. It is used to store the context of the connection, i.e. the login to be used for this cleint. This allows each client connected to the server to contain its own user login.

Responsibilities:

  • Allow units of work to be acquired and pass them the client login's exclusive connection.
  • Forward all requests and queries to its parent server session.

This class is an implementation of {@link oracle.toplink.essentials.sessions.Session}. Please refer to that class for a full API. The public interface should be used.

see
Server
see
oracle.toplink.essentials.sessions.UnitOfWork

Fields Summary
protected ServerSession
parent
protected ConnectionPolicy
connectionPolicy
protected Accessor
writeConnection
protected boolean
isActive
protected oracle.toplink.essentials.internal.sequencing.Sequencing
sequencing
Constructors Summary
public ClientSession(ServerSession parent, ConnectionPolicy connectionPolicy)
INTERNAL: Create and return a new client session.

        super(parent.getProject());
        if (connectionPolicy.isUserDefinedConnection()) {
            // PERF: project only requires clone if login is different
            this.setProject((Project)getProject().clone());
            this.setLogin(connectionPolicy.getLogin());
        }
        this.isActive = true;
        this.externalTransactionController = parent.getExternalTransactionController();
        this.parent = parent;
        this.connectionPolicy = connectionPolicy;
        this.writeConnection = this.accessor; // Uses accessor as write unless is pooled.
        this.accessor = parent.getAccessor(); // This is used for reading only.
        this.name = parent.getName();
        this.profiler = parent.getProfiler();
        this.isInProfile = parent.isInProfile;
        this.commitManager = parent.getCommitManager();
        this.sessionLog = parent.getSessionLog();
        this.eventManager = parent.getEventManager().clone(this);
        this.exceptionHandler = parent.getExceptionHandler();

        getEventManager().postAcquireClientSession();
        incrementProfile(SessionProfiler.ClientSessionCreated);
    
protected ClientSession(oracle.toplink.essentials.sessions.Project project)

        super(project);
    
Methods Summary
public voidafterTransaction(boolean committed, boolean isExternalTransaction)
INTERNAL: Called after transaction is completed (committed or rolled back)

        if (hasWriteConnection()) {
            getParent().afterTransaction(committed, isExternalTransaction, getWriteConnection());
            if (isExternalTransaction) {
                getWriteConnection().afterJTSTransaction();
                releaseWriteConnection();
            }
        }
    
public voidbasicBeginTransaction()
INTERNAL: This is internal to the unit of work and should never be called otherwise.

        // if an exclusve connection is use this client session may have 
        // a connection already
        if (!hasWriteConnection()) {
            // Ensure that the client is logged in for lazy clients.
            if (getConnectionPolicy().isLazy()) {
                getParent().acquireClientConnection(this);
            }
        }
        super.basicBeginTransaction();
    
public voidbasicCommitTransaction()
INTERNAL: This is internal to the unit of work and should not be called otherwise.

        //Only releasee connection when transaction succeeds.  
        //If not, connection will be released in rollback.
        super.basicCommitTransaction();

        // the connection will be released by afterCompletion callback to
        // afterTransaction(., true);
        if (!getParent().getDatasourceLogin().shouldUseExternalTransactionController()) {
            releaseWriteConnection();
        }
        // if there is no external TX controller, then that means we are currently not synchronized
        // with a global JTS transaction.  In this case, there won't be any 'afterCompletion'
        // callbacks so we have to release the connection here.  It is possible (WLS 5.1) to choose
        // 'usesExternalTransactionController' on the login, but still acquire a uow that WON'T be
        // synchronized with a global TX.
        else if (this.getExternalTransactionController() == null) {
            releaseWriteConnection();
        }
    
public voidbasicRollbackTransaction()
INTERNAL: This is internal to the unit of work and should not be called otherwise.

        try {
            //BUG 2660471: Make sure there is an accessor (moved here from Session)
            //BUG 2846785: EXCEPTION THROWN IN PREBEGINTRANSACTION EVENT CAUSES NPE
            if (hasWriteConnection()) {
                super.basicRollbackTransaction();
            }
        } finally {
            // the connection will be released by afterCompletion callback to
            // afterTransaction(., true);
            if (!getParent().getDatasourceLogin().shouldUseExternalTransactionController()) {
                releaseWriteConnection();
            }
            // if there is no external TX controller, then that means we are currently not synchronized
            // with a global JTS transaction.  In this case, there won't be any 'afterCompletion'
            // callbacks so we have to release the connection here.  It is possible (WLS 5.1) to choose
            // 'usesExternalTransactionController' on the login, but still acquire a uow that WON'T be
            // synchronized with a global TX.
            else if (this.getExternalTransactionController() == null) {
                releaseWriteConnection();
            }
        }
    
public voidconnect()
INTERNAL: Connect the session only (this must be the write connection as the read is shared).

        getWriteConnection().connect(getDatasourceLogin(), this);
    
public booleancontainsQuery(java.lang.String queryName)
INTERNAL: Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}. Return true if the pre-defined query is defined on the session.

        boolean containsQuery = getQueries().containsKey(queryName);
        if (containsQuery == false) {
            containsQuery = getParent().containsQuery(queryName);
        }
        return containsQuery;
    
public voiddisconnect()
INTERNAL: Disconnect the accessor only (this must be the write connection as the read is shared).

        getWriteConnection().disconnect(this);
    
protected voidfinalize()
INTERNAL: Release in case not released.

        if (isActive()) {
            release();
        }
    
public AccessorgetAccessor()
INTERNAL: Return the read or write connection depending on the transaction state.

        if (isInTransaction()) {
            return getWriteConnection();
        }
        return super.getAccessor();
    
public ConnectionPolicygetConnectionPolicy()
ADVANCED: This method will return the connection policy that was used during the acquisition of this client session. The properties within the ConnectionPolicy may be used when acquiring an exclusive connection for an IsolatedSession.

        return connectionPolicy;
    
public java.util.MapgetDescriptors()
INTERNAL: Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}. Return all registered descriptors. The clients session inherits its parent's descriptors.

        return getParent().getDescriptors();
    
public oracle.toplink.essentials.internal.sessions.AbstractSessiongetExecutionSession(DatabaseQuery query)
INTERNAL: Gets the session which this query will be executed on. Generally will be called immediately before the call is translated, which is immediately before session.executeCall.

Since the execution session also knows the correct datasource platform to execute on, it is often used in the mappings where the platform is needed for type conversion, or where calls are translated.

Is also the session with the accessor. Will return a ClientSession if it is in transaction and has a write connection.

return
a session with a live accessor
param
query may store session name or reference class for brokers case

        // For CR#4334 if in transaction stay on client session.
        // That way client's write accessor will be used for all queries.
        // This is to preserve transaction isolation levels.
        // For bug 3602222 if a query is executed directly on a client session when
        // in transaction, then dirty data could be put in the shared cache for the
        // client session uses the identity map of its parent.
        // However beginTransaction() is not public API on ClientSession.
        // if fix this could add: && (query.getSession() != this).
        if (isInTransaction()) {
            return this;
        }
        return getParent().getExecutionSession(query);
    
public ServerSessiongetParent()
INTERNAL: Return the parent. This is a server session.

        return parent;
    
public oracle.toplink.essentials.internal.sessions.AbstractSessiongetParentIdentityMapSession(DatabaseQuery query, boolean canReturnSelf, boolean terminalOnly)
INTERNAL: Gets the next link in the chain of sessions followed by a query's check early return, the chain of sessions with identity maps all the way up to the root session.

Used for session broker which delegates to registered sessions, or UnitOfWork which checks parent identity map also.

param
canReturnSelf true when method calls itself. If the path starting at this is acceptable. Sometimes true if want to move to the first valid session, i.e. executing on ClientSession when really should be on ServerSession.
param
terminalOnly return the session we will execute the call on, not the next step towards it.
return
this if there is no next link in the chain

        // Note could return self as ClientSession shares the same identity map
        // as parent.  This reveals a deep problem, as queries will be cached in
        // the Server identity map but executed here using the write connection.
        return getParent().getParentIdentityMapSession(query, canReturnSelf, terminalOnly);
    
public DatabaseQuerygetQuery(java.lang.String name)
INTERNAL: Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}. Return the query from the session pre-defined queries with the given name. This allows for common queries to be pre-defined, reused and executed by name.

        DatabaseQuery query = (DatabaseQuery)super.getQuery(name);
        if (query == null) {
            query = getParent().getQuery(name);
        }

        return query;
    
public DatabaseQuerygetQuery(java.lang.String name, java.util.Vector args)
INTERNAL:

// CR3716; Predrag;
        DatabaseQuery query = super.getQuery(name, args);
        if (query == null) {
            query = getParent().getQuery(name, args);
        }
        return query;
    
public oracle.toplink.essentials.internal.sequencing.SequencinggetSequencing()
INTERNAL: Return the Sequencing object used by the session. Lazy init sequencing to defer from client session creation to improve creation performance.

        // PERF: lazy init defer from constructor, only created when needed.
        if (sequencing == null) {
            initializeSequencing();
        }
        return sequencing;
    
public oracle.toplink.essentials.platform.server.ServerPlatformgetServerPlatform()
INTERNAL: Marked internal as this is not customer API but helper methods for accessing the server platform from within TopLink's other sessions types (ie not DatabaseSession)

        return getParent().getServerPlatform();
    
public java.lang.StringgetSessionTypeString()
INTERNAL: Returns the type of session, its class.

Override to hide from the user when they are using an internal subclass of a known class.

A user does not need to know that their UnitOfWork is a non-deferred UnitOfWork, or that their ClientSession is an IsolatedClientSession.

        return "ClientSession";
    
public AccessorgetWriteConnection()
INTERNAL: Return the connection to be used for database modification.

        return writeConnection;
    
protected booleanhasWriteConnection()
INTERNAL: Return if this session has been connected.

        if (getWriteConnection() == null) {
            return false;
        }

        return getWriteConnection().isConnected();
    
public voidinitializeIdentityMapAccessor()
INTERNAL: Set up the IdentityMapManager. This method allows subclasses of Session to override the default IdentityMapManager functionality.

        this.identityMapAccessor = new ClientSessionIdentityMapAccessor(this);
    
public voidinitializeSequencing()
INTERNAL: was ADVANCED: Creates sequencing object for the session. Typically there is no need for the user to call this method - it is called from the constructor.

        this.sequencing = SequencingFactory.createSequencing(this);
    
public booleanisActive()
INTERNAL: Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}. Return if the client session is actvie (has not been released).

        return isActive;
    
public booleanisClientSession()
INTERNAL: Return if this session is a client session.

        return true;
    
public booleanisConnected()
INTERNAL: Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}. Return if this session has been connected to the database.

        return getParent().isConnected();
    
public voidrelease()
INTERNAL: Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}. Release the client session. This releases the client session back to it server. Normally this will logout of the client session's connection, and allow the client session to garbage collect.

        if (!isActive()) {
            return;
        }
        getEventManager().preReleaseClientSession();

        //removed is Lazy check as we should always release the connection once
        //the client session has been released.  It is also required for the 
        //behaviour of a subclass ExclusiveIsolatedClientSession
        if (hasWriteConnection()) {
            getParent().releaseClientSession(this);
        }

        // we are not inactive until the connection is  released
        setIsActive(false);
        log(SessionLog.FINER, SessionLog.CONNECTION, "client_released");
        getEventManager().postReleaseClientSession();
    
protected voidreleaseWriteConnection()
INTERNAL: This is internal to the unit of work and should not be called otherwise.

        if (getConnectionPolicy().isLazy() && hasWriteConnection()) {
            getParent().releaseClientSession(this);
            setWriteConnection(null);
        }
    
protected voidsetConnectionPolicy(ConnectionPolicy connectionPolicy)
INTERNAL: Set the connection policy.

        this.connectionPolicy = connectionPolicy;
    
protected voidsetIsActive(boolean isActive)
INTERNAL: Set if the client session is actvie (has not been released).

        this.isActive = isActive;
    
protected voidsetParent(ServerSession parent)
INTERNAL: Set the parent. This is a server session.

        this.parent = parent;
    
public voidsetWriteConnection(Accessor writeConnection)
INTERNAL: Set the connection to be used for database modification.

        this.writeConnection = writeConnection;
    
public java.lang.StringtoString()
INTERNAL: Print the connection status with the session.

        StringWriter writer = new StringWriter();
        writer.write(getSessionTypeString());
        writer.write("(");
        writer.write(String.valueOf(getWriteConnection()));
        writer.write(")");
        return writer.toString();