// Copyright (c) 1999, 2000 Oracle Corporation package oracle.jbo.common.ampool; import java.util.Vector; import java.util.Hashtable; import java.util.Stack; import java.util.Properties; import javax.naming.*; import oracle.jbo.*; import oracle.jbo.common.Diagnostic; import oracle.jbo.common.PropertyMetadata; import oracle.jbo.common.JboEnvUtil; import oracle.jbo.common.Configuration; class ReferencedListElement { ReferencedListElement nextElement = null; ApplicationModule appModule = null; } class ApplicationModuleInfo { boolean isCheckedOut = false; SessionCookie mReferencingSessionCookie = null; long timeToCreateMillis = -1; long creationTimeMillis = -1; } class LoadBalanceInfo { private AMHomeDesc[] mDescs; private int mCreationPolicy = ApplicationPoolImpl.CREATION_POLICY_SERIAL; private int mMaxHandlePolicy = ApplicationPoolImpl.MAX_HANDLE_POLICY_SPILL; private boolean mBalanced = false; private int mIndex = -1; private Vector[] mAMInstVecs; LoadBalanceInfo(AMHomeDesc[] descs) { mDescs = descs; mAMInstVecs = new Vector[descs.length]; } int getCreationPolicy() { return mCreationPolicy; } void setCreationPolicy(int creationPolicy) { mCreationPolicy = creationPolicy; } int getMaxHandlePolicy() { return mMaxHandlePolicy; } void setMaxHandlePolicy(int maxHandlePolicy) { mMaxHandlePolicy = maxHandlePolicy; } boolean isBalanced() { return mBalanced; } void setBalanced(boolean balanced) { mBalanced = balanced; } AMHomeDesc getNextHomeDescForCreate() { if (mDescs == null || mDescs.length == 0) { return null; } AMHomeDesc hDesc = null; int tryIndex = mIndex; if (tryIndex < 0) { tryIndex = 0; } else if (getCreationPolicy() == ApplicationPoolImpl.CREATION_POLICY_ROUND_ROBIN) { tryIndex++; } int j; for (j = 0; j < mDescs.length; j++) { if (tryIndex >= mDescs.length) { tryIndex = 0; } if (mAMInstVecs[tryIndex] == null) { mAMInstVecs[tryIndex] = new Vector(); } int numOfInsts = mAMInstVecs[tryIndex].size(); hDesc = mDescs[tryIndex]; if (hDesc.getMaxNumOfInsts() < 0 || numOfInsts < hDesc.getMaxNumOfInsts()) { break; } tryIndex++; } if (j >= mDescs.length) { // All home descs are full return null; } return hDesc; } } /** * This class provides the default implementation of the ApplicationPool interface. *
* View definition of ApplicationPool *
* View Implementation of ApplicationPoolImpl *

* @author Juan Oropeza */ public class ApplicationPoolImpl extends Object implements ApplicationPool { // static final String IS_CHECKED_OUT = "Yes"; // static final String IS_NOT_CHECKED_OUT = "No"; public static int CREATION_POLICY_SERIAL = 0; public static int CREATION_POLICY_ROUND_ROBIN = 1; public static int MAX_HANDLE_POLICY_SPILL = 0; public static int MAX_HANDLE_POLICY_ERROR = 1; private long signature; private Hashtable env; private String poolName; private Vector instances = new Vector(10); private Hashtable userData; private String sConnectString; private String sApplicationModule; private Hashtable mInstanceInfo = new Hashtable(10); private Hashtable mSessionCookies = new Hashtable(10); private ReferencedListElement mReferencedInstanceList; private int cookieNum = 0; private String sUserName; private String sPassword; private LoadBalanceInfo mLBInfo = null; /** * Constructor */ public ApplicationPoolImpl() { signature = System.currentTimeMillis(); } long getSignature() { return signature; } int getNextCookieNum() { int nextCookieNum = -1; synchronized(mSessionCookies) { nextCookieNum = cookieNum++; } return nextCookieNum; } public void initialize(String sPoolName , String sApplicationModule, String sConnectString, Hashtable env) { this.poolName = sPoolName; this.env = env; this.sConnectString = sConnectString; // Bug 1387996 -- Not properly picking up username password from named // database connections (SPM) if (env != null) { String un = (String) env.get(Configuration.DB_USERNAME_PROPERTY); String pw = (String) env.get(Configuration.DB_PASSWORD_PROPERTY); if (un!=null) setUserName(un); if (pw!=null) setPassword(pw); } this.sApplicationModule = sApplicationModule; } public String getApplicationModuleClass() { return this.sApplicationModule; } public String getConnectString() { return this.sConnectString; } public Hashtable getEnvironment() { return this.env; } public synchronized void checkin(ApplicationModule appModule) { // Determine if the pool recognizes this application module // as having been checked out. If not, throw an exception. if (isAvailable(appModule)) { throw new ApplicationPoolException( AMPoolMessageBundle.class , AMPoolMessageBundle.EXC_AMPOOL_INVALID_CHECKIN , new Object[] {poolName}); } SessionCookie cookie = getReferencingSessionCookie(appModule); // Clean up any old session state that may be association with this // application module before returning. When a stateless check-in occurs // it is assumed that there is no longer any application module state // associated with the session. if (cookie.getPassivationId() >= 0) { try { appModule.removeState(cookie.getPassivationId()); } catch(oracle.jbo.pcoll.PCollException pcex) { // Eat the persistence exception if it is related to an invalid root // node. An exception is currently thrown if a non-existing // passivation id is specified. This may occur if the database // administrator has performed some maintenance tasks since the // passivation id was generated. if ((pcex.getErrorCode() != null) && (pcex.getErrorCode().equals(CSMessageBundle.EXC_PCOLL_INVALID_ROOT_NODE))) { Diagnostic.println(new StringBuffer(32) .append("The root passivation record for passivate id, ") .append(cookie.getPassivationId()) .append(", was not located").toString()); } else { throw pcex; } } } removeReferencedInstance(appModule); removeSessionCookie(appModule, cookie); // Rollback the application module first to clean up any potential // database state. This is okay because we have chosen not to retain // application module state. If we do not perform a rollback then // an exception may occur when application module state is activated. appModule.getTransaction().rollback(); disconnect(appModule, false); setAvailable(appModule, true); } /** * Check in and retain the state of the specified application module. This * method generates a cookie for the application module that can be used as * a unique identifier for the application module's session state. Check-in * with session state will also disconnect the application module's JDBC * connection and return the JDBC connection to the JDBC connection pool for * reuse. Consequently, when using this method there must not be any * database state that must be saved across sessions. Examples of database * state include pessimistic locks, open cursors, or posted but uncommited * changes. If any database state must be saved between requests * checkinWithSessionState should not be used. Instead the application * module reference should be maintained by the client until the database * state has been committed/rolled back. * * @param doFailover If true, the application module will be passivated * immediately and the application passivation id will be returned with * the session id. If false, the application module will not be * passivated until it is reused by a session other than the session that * has checked in the application module. * * @returns A unique id representing the session's application module state. * The id may be used to retrieve the session state when checking out * an application module from the pool later in the application life * cycle. */ public synchronized String checkinWithSessionState(ApplicationModule appModule) { // Determine if the pool recognizes this application module // as having been checked out. If not, throw an exception. if (isAvailable(appModule)) { throw new ApplicationPoolException( AMPoolMessageBundle.class , AMPoolMessageBundle.EXC_AMPOOL_INVALID_CHECKIN , new Object[] {poolName}); } StringBuffer returnId = new StringBuffer(); SessionCookie cookie = getReferencingSessionCookie(appModule); // The cookie may have been cleaned up since the application module // was checked out. Create new cookie. if (cookie == null) { cookie = createSessionCookie(appModule); } returnId.append(cookie.getCookieNum()); boolean doFailover = JboEnvUtil.getPropertyAsBoolean( PropertyMetadata.ENV_DO_FAILOVER.pName , Boolean.valueOf(PropertyMetadata.ENV_DO_FAILOVER.pDefault) .booleanValue()); // If failover support has been requested then passivate the // application module before setting it as available. if (doFailover) { Diagnostic.println("Application Module failover is enabled"); doFailover(appModule, cookie); // Append the passivation id to the session id so that it may be used // to activate the application module if the middle tier VM instance // dies. returnId.append(','); returnId.append(String.valueOf(cookie.mPassivationId)); } // Release the application module's JDBC connection to the connection // pool. Retain the application module state so that the application // does not have to be activated if it is requested by the same session. try { disconnect(appModule, true); } catch (JboException ex) { // Disconnect the application module without retaining AM state if // a database state exception is thrown. if ((ex.getErrorCode() != null) && (ex.getErrorCode().equals(CSMessageBundle.EXC_DATABASE_STATE_EXISTS))) { Diagnostic.println("Database state was detected while disconnecting the application module's connection"); // If the application module was not already passivated then // passivate. if (!doFailover) { Diagnostic.println("Passivating the application module state."); doFailover(appModule, cookie); // Append the passivation id to the session id so that it may be used // to activate the application module if the middle tier VM instance // dies. returnId.append(','); returnId.append(String.valueOf(cookie.mPassivationId)); } // Rollback the application module first to clean up any potential // database state. This is okay because we have chosen not to retain // application module state. If we do not perform a rollback then // an exception may occur when application module state is activated. appModule.getTransaction().rollback(); disconnect(appModule, false); // Mark the cookie's doActivate flag to indicate that activation // must occur upon checkout. cookie.mDoActivate = true; } else { throw ex; } } setAvailable(appModule, true); return returnId.toString(); } public long getTimeToCreateMillis(ApplicationModule instance) { ApplicationModuleInfo info = (ApplicationModuleInfo)mInstanceInfo.get(instance); return info.timeToCreateMillis; } public long getCreationTimeMillis(ApplicationModule instance) { ApplicationModuleInfo info = (ApplicationModuleInfo)mInstanceInfo.get(instance); return info.creationTimeMillis; } public boolean isAvailable(ApplicationModule instance) { synchronized(instance) { ApplicationModuleInfo info = (ApplicationModuleInfo)mInstanceInfo.get(instance); return (!info.isCheckedOut); } } public void setAvailable(ApplicationModule instance, boolean bSet) { synchronized(instance) { ApplicationModuleInfo info = (ApplicationModuleInfo)mInstanceInfo.get(instance); info.isCheckedOut = (!bSet); } } public synchronized ApplicationModule createNewInstance() throws Exception { // This method does not check out the new application module instance // that is created. This is because the method is being used by // checkout if an available or referenced instance is not located. // Perhaps this method should be made protected to prevent improper /// use by client applications. // create a new instance using the connect info Context initialContext; if(JboEnvUtil.inJServer()) { initialContext = oracle.jbo.server.xml.aurora.AuroraJNDIContextHelper.createContext(env); } else { initialContext = new InitialContext(env); } ApplicationModuleHome home = (ApplicationModuleHome) initialContext.lookup(sApplicationModule); long start = System.currentTimeMillis(); ApplicationModule am = home.create(); long end = System.currentTimeMillis(); connect(am); ApplicationModuleInfo info = new ApplicationModuleInfo(); info.timeToCreateMillis = end - start; info.creationTimeMillis = end; mInstanceInfo.put(am, info); // add instance to collection instances.addElement(am); setAvailable(am, true); return am; } public synchronized ApplicationModule checkout() throws Exception { ApplicationModule rtn = null; ApplicationModule current = null; boolean isAvailable = true; for (int i = 0 ; i < instances.size(); i ++) { current = (ApplicationModule) instances.elementAt(i); if ((current != null) && (isAvailable(current)) && (!isReferenced(current))) { Diagnostic.println("Recycling an unreferenced, available pool instance"); rtn = current; reconnect(rtn); break; } } // If an available, unreferenced application module was not located above // then grab the first referenced application module off of the FIFO // stack. Use a FIFO stack to ensure that the oldest references are // recycled first. if (rtn == null) { ReferencedListElement listElement = mReferencedInstanceList; int recycleThreshold = JboEnvUtil.getPropertyAsInt( PropertyMetadata.ENV_POOL_RECYCLE_THRESHOLD.pName , Integer.valueOf(PropertyMetadata.ENV_POOL_RECYCLE_THRESHOLD.pDefault) .intValue()); // If the number of pool instances is less than the recycle threshold // then do not attempt to recycle a referenced application module. // A new application module will be created below. if (getInstanceCount() >= recycleThreshold) { while (listElement != null) { current = listElement.appModule; if ((current != null) && (isAvailable(current))) { Diagnostic.println("Recycling a referenced, available pool instance"); rtn = current; reconnect(rtn); // Remove the application module's session references SessionCookie oldCookie = getReferencingSessionCookie(rtn); boolean doFailover = JboEnvUtil.getPropertyAsBoolean( PropertyMetadata.ENV_DO_FAILOVER.pName , Boolean.valueOf(PropertyMetadata.ENV_DO_FAILOVER.pDefault) .booleanValue()); // If the deferred passivation has been specified then passivate // the referenced application module's state before continuing. // Otherwise, the application module's state has already been // passivated. if (!doFailover) { int passivationId = rtn.passivateState(null); oldCookie.setPassivationId(passivationId); } // Remove the instance from the referenced list. removeReferencedInstance(rtn); oldCookie.setApplicationModule(null); // Rollback. This is necessary to remove any // unposted transaction validation listeners which may still be // registered on a stateful application module's transaction. rtn.getTransaction().rollback(); rtn.clearVOCaches(null, true); // Clear the entity caches as well. rtn.getTransaction().clearEntityCache(null); break; } listElement = listElement.nextElement; } } } // If an application module has still not been located then create a new // instance. if (rtn == null) { Diagnostic.println("Creating a new pool instance"); rtn = createNewInstance(); } // Create a new session cookie for this checkout. Associate the new // session cookie with the checked out application module. createSessionCookie(rtn); setAvailable(rtn, false); // Immediately add the application module to the referenced instance list. addReferencedInstance(rtn); return rtn; } public synchronized void releaseInstances() { int nSize = instances.size(); for (int i = 0; i < nSize; i++) { ApplicationModule instance = (ApplicationModule) instances.elementAt(i); instance.remove(); } for (int i = nSize - 1; i >= 0; i--) { instances.removeElementAt(i); } mInstanceInfo.clear(); mSessionCookies.clear(); mReferencedInstanceList = null; } public synchronized int getAvailableNumPools() { int count = 0; ApplicationModule current = null; for(int i = 0 ; i < instances.size(); i++) { current = (ApplicationModule) instances.elementAt(i); if (isAvailable(current)) { count++; } } return count; } public synchronized int getInstanceCount() { return instances.size(); } public synchronized ApplicationModule getInstance(int nIndex) { return (ApplicationModule) instances.elementAt(nIndex); } public synchronized ApplicationModule checkout(String sessionId) { ApplicationModule rtn = null; Integer passivationId = null; // Parse the session id before beginning. The session id may be a comma // delimited structure consisting of a session id and a passivation id. // This will occur if immediate passivation was requested by the client. int commaIndex = sessionId.indexOf(','); if (commaIndex >= 0) { passivationId = new Integer(sessionId.substring(commaIndex + 1)); sessionId = sessionId.substring(0, commaIndex); } SessionCookie cookie = (SessionCookie)mSessionCookies.get(sessionId); rtn = (cookie != null ? cookie.getApplicationModule() : null); if ((rtn != null) && (isAvailable(rtn))) { Diagnostic.println("Reusing cached session instance"); setAvailable(rtn, false); reconnect(rtn); // If the doActivate flag is marked true on the session cookie // then activate the application module. The application module // must have been passivated because database state existed. if (cookie.mDoActivate) { try { rtn.activateState(passivationId.intValue(), true); } catch(oracle.jbo.pcoll.PCollException pcex) { // Eat the persistence exception if it is related to an invalid root // node. An exception is currently thrown if a non-existing // passivation id is specified. This may occur if the database // administrator has performed some maintenance tasks since the // passivation id was generated. if ((pcex.getErrorCode() != null) && (pcex.getErrorCode().equals(CSMessageBundle.EXC_PCOLL_INVALID_ROOT_NODE))) { Diagnostic.println(new StringBuffer(32) .append("The root passivation record for passivate id, ") .append(passivationId) .append(", was not located").toString()); } else { throw pcex; } } cookie.mDoActivate = false; } // Strange behaviour could occur if an old cookie that was not // generated by this VM's cookie sequence matches that of a different // client session's cookie. // // If the second client session's application module is available then // the implementation below will reuse the application module as it were // owned by the first client's session (this means any state specified // in the passivation id will not be activated). If failover support has // been specified the second client's state will have been passivated // correctly, but the session conflict may cause problems when the // application module is returned. In order to prevent this create a // new session cookie. SessionCookie newCookie = createSessionCookie(rtn); // Transfer the old cookie's passivation id to the new session cookie. newCookie.setPassivationId(cookie.getPassivationId()); // Set the old cookie as not referencing the checked out application // module instance. The old cookie is maintained in case an error // occurs before the application module is checked in and the new // session cookie id is returned to pool client. cookie.setApplicationModule(null); // Assign the newCookie reference to the local cookie reference. cookie = newCookie; // Finally move the application module to the end of the referenced // list. removeReferencedInstance(rtn); addReferencedInstance(rtn); } // An application module was not located for the specified session. // Checkout any application module. else { try { rtn = checkout(); } catch (Exception ex) { Diagnostic.printStackTrace(ex); ApplicationPoolException aex = new ApplicationPoolException( AMPoolMessageBundle.class , AMPoolMessageBundle.EXC_AMPOOL_CHECKOUT_FAILED , new Object[] {poolName}); aex.addToDetails(ex); throw aex; } // If a cookie was located for the specified session and a // passivation id was not specified then failover support // must have been disabled. Get the passivation id from the // session cookie. Leave the old cookie around so that the session // state may still be activiated if an error occurs before the // application module is checked back into the pool and the new cookie // id is returned to the pool client. The cookie should not reference // an application module or else the top portion of this condition // would have been executed. Consequently, the cookie does need // its referencing application module reset. if ((cookie != null) && (passivationId == null) && (cookie.getPassivationId() >= 0)) { passivationId = new Integer(cookie.getPassivationId()); } // Get the new session cookie that was generated during checkout. cookie = (SessionCookie)getReferencingSessionCookie(rtn); // If the passivation id is not null then the application module must // have been passivated. Activitate the applciation module if the // referencing session id of the application module is not the specified // session id. This is an optimization to prevent excessive activation // of application modules. if (passivationId != null) { // Set the cookie passivation id with the specified passivation id. // This is necessary because a new cookie has been generated for // the requesting session. Future logic that uses the session // cookie must be aware that the session's state has already been // passivated. cookie.setPassivationId(passivationId.intValue()); try { rtn.activateState(passivationId.intValue(), true); } catch(oracle.jbo.pcoll.PCollException pcex) { // Eat the persistence exception if it is related to an invalid root // node. An exception is currently thrown if a non-existing // passivation id is specified. This may occur if the database // administrator has performed some maintenance tasks since the // passivation id was generated. if ((pcex.getErrorCode() != null) && (pcex.getErrorCode().equals(CSMessageBundle.EXC_PCOLL_INVALID_ROOT_NODE))) { Diagnostic.println(new StringBuffer(32) .append("The root passivation record for passivate id, ") .append(passivationId) .append(", was not located").toString()); } else { throw pcex; } } cookie.mDoActivate = false; } } return rtn; } public synchronized String getPoolName() { return poolName; } /** * returns the User Data hashtable. This is a generic container for * any settings the user would like to associate with this application instance. */ public Hashtable getUserData() { return userData; } /** * Replaces the userData with the new Hashtable. */ public void setUserData(Hashtable data) { this.userData = data; } /** * returns the user name **/ public String getUserName() { return this.sUserName; } public void setUserName(String sUser) { this.sUserName = sUser; } public void setPassword(String sPassword) { this.sPassword = sPassword; } /** * returns the password **/ public String getPassword() { return this.sPassword; } public void commitAndSyncCache(ApplicationModule instance) { int snapId = instance.getTransaction().commitAndSaveChangeSet(); if (snapId >= 0) { for(int i = 0 ; i < instances.size(); i++) { ApplicationModule current = (ApplicationModule) instances.elementAt(i); if (current != instance) { current.getTransaction().applyChangeSet(snapId); } } instance.getTransaction().removeChangeSet(snapId); } } private SessionCookie getReferencingSessionCookie(ApplicationModule instance) { ApplicationModuleInfo info = (ApplicationModuleInfo)mInstanceInfo.get(instance); return info.mReferencingSessionCookie; } private void setReferencingSessionCookie( ApplicationModule instance , SessionCookie cookie) { ApplicationModuleInfo info = (ApplicationModuleInfo)mInstanceInfo.get(instance); info.mReferencingSessionCookie = cookie; } private boolean isReferenced(ApplicationModule instance) { ApplicationModuleInfo info = (ApplicationModuleInfo)mInstanceInfo.get(instance); return (info.mReferencingSessionCookie != null); } private ApplicationModule getReferencedInstance() { // Return the next referenced application module in the reference // application module linked list. Referenced application modules are // those application modules that may still have a weak session reference. // These application modules are not recycled by the pool until there // are not unreferenced, checked out application modules available. // Referenced application modules are returned in FIFO fashion to ensure // that the oldest reference is recycled first. ApplicationModule rtn = null; if (mReferencedInstanceList != null) { rtn = mReferencedInstanceList.appModule; } return rtn; } private ApplicationModule removeReferencedInstance( ApplicationModule appModule) { ApplicationModule rtn = null; ReferencedListElement lastElement = null; ReferencedListElement element = mReferencedInstanceList; while (element != null) { if (appModule == element.appModule) { rtn = element.appModule; // Remove the element from the linked list if (lastElement != null) { lastElement.nextElement = element.nextElement; } else { mReferencedInstanceList = null; } break; } lastElement = element; element = element.nextElement; } return rtn; } private void addReferencedInstance(ApplicationModule appModule) { ApplicationModule rtn = null; ReferencedListElement newElement = new ReferencedListElement(); newElement.appModule = appModule; // Get the last element ReferencedListElement element = mReferencedInstanceList; ReferencedListElement lastElement = null; while (element != null) { // Keep an eye out for an existing entry. If one is found // simply return. if (element.appModule == appModule) { return; } lastElement = element; element = element.nextElement; } if (lastElement != null) { lastElement.nextElement = newElement; } else { mReferencedInstanceList = newElement; } } private SessionCookie createSessionCookie(ApplicationModule appModule) { SessionCookie cookie = new SessionCookie(this); mSessionCookies.put(cookie.toString(), cookie); setReferencingSessionCookie(appModule, cookie); cookie.setApplicationModule(appModule); return cookie; } private void removeSessionCookie( ApplicationModule appModule, SessionCookie cookie) { // Clean up the cookie. mSessionCookies.remove(cookie.toString()); cookie.setApplicationModule(null); setReferencingSessionCookie(appModule, null); } private void doFailover(ApplicationModule appModule, SessionCookie cookie) { // After passivating the application module attempt to clean up any // records associated with previously passivated state. State may not be // removed if the VM instance has died (pass a previous state to this // method? Add logic to the application registry to handle this?). // JRS TODO: This logic should occur AFTER passivation in order to // ensure failover support if an exception occurs during passivation. // However, a bug in the passivation framework that prevents an // application module instance from being passivated multiple times // has required that the logic appear before passivation for now. if (cookie.getPassivationId() >= 0) { try { appModule.removeState(cookie.getPassivationId()); } catch(oracle.jbo.pcoll.PCollException pcex) { // Eat the persistence exception if it is related to an invalid root // node. An exception is currently thrown if a non-existing // passivation id is specified. This may occur if the database // administrator has performed some maintenance tasks since the // passivation id was generated. if ((pcex.getErrorCode() != null) && (pcex.getErrorCode().equals(CSMessageBundle.EXC_PCOLL_INVALID_ROOT_NODE))) { Diagnostic.println(new StringBuffer(32) .append("The root passivation record for passivate id, ") .append(cookie.getPassivationId()) .append(", was not located").toString()); } else { throw pcex; } } } int passivationId = appModule.passivateState(null); // Store the passivation id on the application module cookie so that // we know the last passivation id. cookie.setPassivationId(passivationId); } /** * Establish the inital application module JDBC connection. This method is * invoked by the application module pool when new application module * instances are instantiated. Application developers who would like to * plug a custom connection framework into the application module pool may * override this method. */ protected void connect(ApplicationModule appModule) { if (!appModule.getTransaction().isConnected()) { Diagnostic.println("AM pool is establishing an application module connection"); Properties jdbcProp = new Properties(); if (sUserName != null && sPassword != null) { jdbcProp.put(Configuration.DB_USERNAME_PROPERTY, sUserName); jdbcProp.put(Configuration.DB_PASSWORD_PROPERTY, sPassword); } appModule.getTransaction().connect(sConnectString, jdbcProp); } } /** * Re-establish an application module's JDBC connection. This method is * invoked by the application module pool when an application module instance * is recycled by the pool. Application developers who would like to * plug a custom connection framework into the application module pool may * override this method. */ protected void reconnect(ApplicationModule appModule) { if (!appModule.getTransaction().isConnected()) { Diagnostic.println("AM pool is re-establishing an application module connection"); try { appModule.getTransaction().reconnect(); } catch (NotConnectedException ex) { // If a NotConnectedException is thrown then reconnect using // the reconnect method on NullDBTransactionImpl. The application // module must have been disconnected without retainState specified. appModule.getTransaction().reconnect(true); } } } /** * Disconnect an application module from its JDBC connection. This method is * invoked by the application module pool when an application module instance * is checked into the pool. The method checks the application property * jbo.doconnectionpooling before disconnecting the application * module. Application developers who would like to plug a custom connection * framework into the application module pool may override this method. * * @param retainState Indicates whether the state of the application * module's caches should be retained while disconnecting. If true, the * application module's Transaction should have not database state. */ protected void disconnect(ApplicationModule appModule, boolean retainState) { if (retainState) { // If retainState has been specified then check the // jbo.doconnectionpooling property before attempting to disconnect // the application module. The retain state flag will only be // true when the pool is managing an application module's state. String doDisconnectStr = (String)env.get(PropertyMetadata.ENV_DO_CONNECTION_POOLING.pName); boolean doDisconnect = (doDisconnectStr == null) ? Boolean.valueOf(PropertyMetadata.ENV_DO_CONNECTION_POOLING.pDefault) .booleanValue() : Boolean.valueOf(doDisconnectStr).booleanValue(); if (doDisconnect) { Diagnostic.println("AM pool is disconnecting an application module connection"); appModule.getTransaction().disconnect(true); } } else { // If the retainState has not been specified then disconnect the // application module regardless of the value of the // jbo.doconnectionpooling flag. The retainState flag is only // specified when the pool is not managing the application // module state. Diagnostic.println("AM pool is disconnecting an application module connection"); appModule.getTransaction().disconnect(); } } }