All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.toplink.essentials.threetier.ClientSession Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
 * 
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package oracle.toplink.essentials.threetier;

import java.util.*;
import java.io.*;
import oracle.toplink.essentials.platform.server.ServerPlatform;
import oracle.toplink.essentials.queryframework.*;
import oracle.toplink.essentials.exceptions.*;
import oracle.toplink.essentials.internal.databaseaccess.*;
import oracle.toplink.essentials.internal.sequencing.Sequencing;
import oracle.toplink.essentials.internal.sequencing.SequencingFactory;
import oracle.toplink.essentials.logging.SessionLog;
import oracle.toplink.essentials.internal.sessions.*;
import oracle.toplink.essentials.sessions.Project;
import oracle.toplink.essentials.sessions.SessionProfiler;
import 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 */ public class ClientSession extends AbstractSession { protected ServerSession parent; protected ConnectionPolicy connectionPolicy; protected Accessor writeConnection; protected boolean isActive; protected Sequencing sequencing; /** * INTERNAL: * Create and return a new client session. */ public ClientSession(ServerSession parent, ConnectionPolicy connectionPolicy) { 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); } /** * INTERNAL: * Called after transaction is completed (committed or rolled back) */ public void afterTransaction(boolean committed, boolean isExternalTransaction) { if (hasWriteConnection()) { getParent().afterTransaction(committed, isExternalTransaction, getWriteConnection()); if (isExternalTransaction) { getWriteConnection().afterJTSTransaction(); releaseWriteConnection(); } } } /** * INTERNAL: * This is internal to the unit of work and should never be called otherwise. */ public void basicBeginTransaction() { // 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(); } /** * INTERNAL: * This is internal to the unit of work and should not be called otherwise. */ public void basicCommitTransaction() { //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(); } } /** * INTERNAL: * This is internal to the unit of work and should not be called otherwise. */ public void basicRollbackTransaction() { 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(); } } } /** * INTERNAL: * Connect the session only (this must be the write connection as the read is shared). */ public void connect() throws DatabaseException { getWriteConnection().connect(getDatasourceLogin(), this); } /** * 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. */ public boolean containsQuery(String queryName) { boolean containsQuery = getQueries().containsKey(queryName); if (containsQuery == false) { containsQuery = getParent().containsQuery(queryName); } return containsQuery; } /** * INTERNAL: * Disconnect the accessor only (this must be the write connection as the read is shared). */ public void disconnect() throws DatabaseException { getWriteConnection().disconnect(this); } /** * INTERNAL: * Release in case not released. */ protected void finalize() throws DatabaseException { if (isActive()) { release(); } } /** * INTERNAL: * Return the read or write connection depending on the transaction state. */ public Accessor getAccessor() { if (isInTransaction()) { return getWriteConnection(); } return super.getAccessor(); } /** * 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. */ public ConnectionPolicy getConnectionPolicy() { return connectionPolicy; } /** * 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. */ public Map getDescriptors() { return getParent().getDescriptors(); } /** * 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 */ public AbstractSession getParentIdentityMapSession(DatabaseQuery query, boolean canReturnSelf, boolean terminalOnly) { // 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); } /** * INTERNAL: * Search for and return the user defined property from this client session, if it not found then search for the property * from parent. */ public Object getProperty(String name){ Object propertyValue = super.getProperties().get(name); if (propertyValue == null) { propertyValue = getParent().getProperty(name); } return propertyValue; } /** * 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 */ public AbstractSession getExecutionSession(DatabaseQuery query) { // 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); } /** * INTERNAL: * Return the parent. * This is a server session. */ public ServerSession getParent() { return parent; } /** * 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. */ public DatabaseQuery getQuery(String name) { DatabaseQuery query = (DatabaseQuery)super.getQuery(name); if (query == null) { query = getParent().getQuery(name); } return query; } /** * INTERNAL: */ public DatabaseQuery getQuery(String name, Vector args) {// CR3716; Predrag; DatabaseQuery query = super.getQuery(name, args); if (query == null) { query = getParent().getQuery(name, args); } return query; } /** * 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. */ public void initializeSequencing() { this.sequencing = SequencingFactory.createSequencing(this); } /** * INTERNAL: * Return the Sequencing object used by the session. * Lazy init sequencing to defer from client session creation to improve creation performance. */ public Sequencing getSequencing() { // PERF: lazy init defer from constructor, only created when needed. if (sequencing == null) { initializeSequencing(); } return sequencing; } /** * 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) */ public ServerPlatform getServerPlatform(){ return getParent().getServerPlatform(); } /** * 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. */ public String getSessionTypeString() { return "ClientSession"; } /** * INTERNAL: * Return the connection to be used for database modification. */ public Accessor getWriteConnection() { return writeConnection; } /** * INTERNAL: * Return if this session has been connected. */ protected boolean hasWriteConnection() { if (getWriteConnection() == null) { return false; } return getWriteConnection().isConnected(); } /** * INTERNAL: * Set up the IdentityMapManager. This method allows subclasses of Session to override * the default IdentityMapManager functionality. */ public void initializeIdentityMapAccessor() { this.identityMapAccessor = new ClientSessionIdentityMapAccessor(this); } /** * 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). */ public boolean isActive() { return isActive; } /** * INTERNAL: * Return if this session is a client session. */ public boolean isClientSession() { return true; } /** * INTERNAL: * Was PUBLIC: customer will be redirected to {@link oracle.toplink.essentials.sessions.Session}. * Return if this session has been connected to the database. */ public boolean isConnected() { return getParent().isConnected(); } /** * 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. */ public void release() throws DatabaseException { 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(); } /** * INTERNAL: * This is internal to the unit of work and should not be called otherwise. */ protected void releaseWriteConnection() { if (getConnectionPolicy().isLazy() && hasWriteConnection()) { getParent().releaseClientSession(this); setWriteConnection(null); } } /** * INTERNAL: * Set the connection policy. */ protected void setConnectionPolicy(ConnectionPolicy connectionPolicy) { this.connectionPolicy = connectionPolicy; } /** * INTERNAL: * Set if the client session is actvie (has not been released). */ protected void setIsActive(boolean isActive) { this.isActive = isActive; } /** * INTERNAL: * Set the parent. * This is a server session. */ protected void setParent(ServerSession parent) { this.parent = parent; } /** * INTERNAL: * Set the connection to be used for database modification. */ public void setWriteConnection(Accessor writeConnection) { this.writeConnection = writeConnection; } /** * INTERNAL: * Print the connection status with the session. */ public String toString() { StringWriter writer = new StringWriter(); writer.write(getSessionTypeString()); writer.write("("); writer.write(String.valueOf(getWriteConnection())); writer.write(")"); return writer.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy