alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (PersistenceManagerImpl.java)

This example Glassfish source code file (PersistenceManagerImpl.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

class, exception, io, iterator, noi18n, noi18n, object, object, persistencecapable, persistencecapable, query, queryimpl, reflection, statemanager, statemanager, string, transaction, util

The Glassfish PersistenceManagerImpl.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. 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_1_1.html
 * or packager/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 packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [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.
 */

/*
 * PersistenceManagerimpl.java
 *
 * Created on March 6, 2000
 */

package com.sun.jdo.spi.persistence.support.sqlstore.impl;

import com.sun.jdo.api.persistence.support.*;
import com.sun.jdo.api.persistence.support.Transaction;
import com.sun.jdo.spi.persistence.support.sqlstore.*;
import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceCapable;
import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager;
import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManagerFactory;
import com.sun.jdo.spi.persistence.support.sqlstore.ejb.EJBHelper;
import com.sun.jdo.spi.persistence.support.sqlstore.query.QueryImpl;
import com.sun.jdo.spi.persistence.utility.NullSemaphore;
import com.sun.jdo.spi.persistence.utility.Semaphore;
import com.sun.jdo.spi.persistence.utility.SemaphoreImpl;
import com.sun.jdo.spi.persistence.utility.logging.Logger;

import org.glassfish.persistence.common.I18NHelper;
import javax.transaction.Status;
import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;

public class PersistenceManagerImpl implements PersistenceManager {
    /**
     * True if this PersistenceManager is closed
     */
    private boolean _isClosed = true;

    // Current wrapper
    private PersistenceManagerWrapper current = null;

    // Reference to the associated JTA Transaction if any
    private javax.transaction.Transaction _jta = null;

    /**
     * Reference to global PersistenceStore
     */
    private PersistenceStore _store = null;

    /**
     * Associated Transaction
     */
    private TransactionImpl _transaction = null;

    /**
     * PersistenceManagerFactory that created (and could be pooling)
     * this PersistenceManager
     */
    private PersistenceManagerFactory persistenceManagerFactory = null;


    /**
     * List of all Persistent instances used
     * in this Transaction not yet flushed to the datastore.
     */
    private List _txCache;

    /**
     * List of all Persistent instances used
     * in this Transaction.
     */
    private Set _flushedCache;

    /**
     * Map of Persistent instances accessed by this PersistenceManager. Ideally it should be
     * a weak-value HashMap to allow for garbage collection of instances that are not
     * referenced any more. java.util.WeakHashMap is a weak-key HashMap and thus does not
     * solve this purpose.
     */
    private Map _weakCache;

    /**
     * Intended to be set to true if there is an exception during flush in
     * {@link #beforeCompletion}. If true, then the Version Consistency cache
     * should be have instances removed during
     * {@link #afterCompletion}.
     */
    private boolean cleanupVersionConsistencyCache = false;

    //
    // Properties for controlling construction of caches.
    // For the integer properties, we can use Integer.getInteger.  There is
    // no corresponding method for floats :-(
    //

    /**
     * Properties with "dirtyCache" in their name apply to the _txCache.
     * This initializes the _txCache's initialCapacity.  If unspecified, uses
     * 20.
     */
    private static final int _txCacheInitialCapacity = Integer.getInteger(
      "com.sun.jdo.api.persistence.support.PersistenceManager.dirtyCache.initialCapacity", // NOI18N
      20).intValue();

    /**
     * Properties with "transactionalCache" in their name apply to the _flushedCache.
     * This initializes the _flushedCache's initialCapacity.  If unspecified,
     * uses 20.
     */
    private static final int _flushedCacheInitialCapacity = Integer.getInteger(
      "com.sun.jdo.api.persistence.support.PersistenceManager.transactionalCache.initialCapacity", // NOI18N
      20).intValue();

    /**
     * Properties with "transactionalCache" in their name apply to the _flushedCache.
     * This initializes the _flushedCache's loadFactor.  If unspecified, uses
     * 0.75, which is the default load factor for a HashSet.
     */
    private static final float _flushedCacheLoadFactor;

    static {
        float f = (float) 0.75;
        try {
            f =
                Float.valueOf(
                  System.getProperty(
                    "com.sun.jdo.api.persistence.support.PersistenceManager.transactionalCache.loadFactor", // NOI18N
                    "0.75")).floatValue(); // NOI18N
        } finally {
            _flushedCacheLoadFactor = f;
        }
    }

    /**
     * Properties with "globalCache" in their name apply to the _weakCache.
     * This initializes the _weakCache's initialCapacity.  If unspecified,
     * uses 20.
     */
    private static final int _weakCacheInitialCapacity = Integer.getInteger(
      "com.sun.jdo.api.persistence.support.PersistenceManager.globalCache.initialCapacity", // NOI18N
      20).intValue();

    /**
     * Properties with "globalCache" in their name apply to the _weakCache.
     * This initializes the _weakCache's loadFactor.  If unspecified, uses
     * 0.75, which is the default load factor for a WeakHashMap.
     */
    private static final float _weakCacheLoadFactor;

    static {
        float f = (float) 0.75;
        try {
            f =
                Float.valueOf(
                  System.getProperty(
                    "com.sun.jdo.api.persistence.support.PersistenceManager.globalCache.loadFactor", // NOI18N
                    "0.75")).floatValue(); // NOI18N
        } finally {
            _weakCacheLoadFactor = f;
        }
    }

    /** Collection of Query instances created for this pm. */
    private Collection queries = new ArrayList();

    /**
     * Flag for Query
     */
    private boolean _ignoreCache = true;

    /**
     * Flag for optimistic transaction
     */
    private boolean _optimistic = true;

    /**
     * Flag for supersedeDeletedInstance
     */
    private boolean _supersedeDeletedInstance = true;

    /**
     * Flag for requireCopyObjectId
     */
    private boolean _requireCopyObjectId = true;

    /**
     * Flag for requireTrackedSCO
     */
    private boolean _requireTrackedSCO = true;

    /**
     * Flag for nontransactionalRead
     */
    private boolean _nontransactionalRead = true;

    /**
     * Flag for active transaction
     */
    private boolean _activeTransaction = false;

    /**
     * User Object
     */
    private Object _userObject = null;

    /**
     * Flag for commit process
     */
    private boolean _insideCommit = false;

    /**
     * Flag for flush processing
     */
    private boolean _insideFlush = false;

    /**
     * Pattern for OID class names
     */
    private static final String oidName_OID = "OID";// NOI18N
    private static final String oidName_KEY = "KEY";// NOI18N

    /**
     * Properies object
     */
    private Properties _properties = null;

    /**
     * Lock used for synchronizing access to the _txCache and _weakCache
     */
    private final Semaphore _cacheLock;

    /**
     * Lock used for synchronizing field updates. It should be used
     * at the discretion of the StateManager.
     */
    private final Semaphore _fieldUpdateLock;

    /**
     * Lock used for implementing read-write barrier.
     */
    private Object _readWriteLock = new Object();

    /**
     * The count for the current reader (> 0) or writer (< 0)
     * Note that the exclusive lock can go multi-level deep
     * as long as the same thread is acquiring it.
     */
    private long _readWriteCount = 0;

    /**
     * The number of threads that are currently waiting on
     * the _readWriteLock.
     */
    private long _waiterCount = 0;

    /**
     * The thread that has the write (exclusive) lock.
     */
    private Thread _exclusiveLockHolder = null;

    /** Indicates if this PM is running in a multithreaded environment, i.e.,
     * if it has to do locking.
     */
    private final boolean _multithreaded;

    /**
     * The logger
     */
    private static Logger logger = LogHelperPersistenceManager.getLogger();

    /**
     * I18N message handler
     */
    private final static ResourceBundle messages = I18NHelper.loadBundle(
            "com.sun.jdo.spi.persistence.support.sqlstore.Bundle",  // NOI18N
            PersistenceManagerImpl.class.getClassLoader());

    /**
     * Constructor
     */
    PersistenceManagerImpl(PersistenceManagerFactory pmf, javax.transaction.Transaction t,
                           String username, String password) {
        persistenceManagerFactory = pmf;

        // Initialize caches as per property values.
        if (logger.isLoggable(Logger.FINEST)) {
            Object[] items = new Object[] { new Integer(_txCacheInitialCapacity),
                                            new Integer(_flushedCacheInitialCapacity),
                                            new Float(_flushedCacheLoadFactor),
                                            new Integer(_weakCacheInitialCapacity),
                                            new Float(_weakCacheLoadFactor) };
            logger.finest("sqlstore.persistencemgr.cacheproperties", items); // NOI18N
        }
        _txCache = new ArrayList(_txCacheInitialCapacity);
        _flushedCache = new LinkedHashSet(_flushedCacheInitialCapacity, _flushedCacheLoadFactor);
        _weakCache = new HashMap(_weakCacheInitialCapacity, _weakCacheLoadFactor);

        // create new Transaction object and set defaults

        _transaction = new TransactionImpl(this,
                username, password, TransactionImpl.TRAN_DEFAULT_TIMEOUT); // VERIFY!!!!

        _ignoreCache = pmf.getIgnoreCache();
        _optimistic = pmf.getOptimistic();
        _nontransactionalRead = pmf.getNontransactionalRead();
        _supersedeDeletedInstance = pmf.getSupersedeDeletedInstance();
        _requireCopyObjectId = pmf.getRequireCopyObjectId();
        _requireTrackedSCO = pmf.getRequireTrackedSCO();

        this._jta = t;	// if null, nothing is changed
        _isClosed = false;

        _multithreaded = ( ! EJBHelper.isManaged());

        if (_multithreaded) {
            _cacheLock =
                new SemaphoreImpl("PersistenceManagerImpl.cacheLock"); // NOI18N
            _fieldUpdateLock =
                new SemaphoreImpl("PersistenceManagerImpl.fieldUpdateLock"); // NOI18N
        } else {
            if (_jta == null) {
                // Non-transactional PersistenceManager can be used in a multithreaded
                // environment.
                _cacheLock =
                    new SemaphoreImpl("PersistenceManagerImpl.cacheLock"); // NOI18N
            } else {
                _cacheLock =
                    new NullSemaphore("PersistenceManagerImpl.cacheLock"); // NOI18N
            }
            _fieldUpdateLock =
                new NullSemaphore("PersistenceManagerImpl.fieldUpdateLock"); // NOI18N
        }
    }

    /**
     *
     */
    protected void setStore(PersistenceStore store) {
        _store = store;
    }

    /**
     *
     */
    protected PersistenceStore getStore() {
        return _store;
    }

    /**
     *
     */
    protected boolean getIgnoreCache() {
        return _ignoreCache;
    }

    /**
     *
     */
    protected boolean verify(String username, String password) {
        return _transaction.verify(username, password);
    }

    /**
     *
     */
    public boolean isClosed() {
        return _isClosed;
    }

    /**
     * Force to close the persistence manager. Called by
     * TransactionImpl.afterCompletion in case of the CMT transaction
     * and the status value passed to the method cannot be resolved.
     */
    public void forceClose() {

        // Return to pool - TBD if we use pooling of free PMs.
        //persistenceManagerFactory.returnToPool((com.sun.jdo.api.persistence.support.PersistenceManager)this);

        persistenceManagerFactory.releasePersistenceManager(this, _jta);

        // Closing PMWrappers need isClosed() to return true to avoid
        // endless recursion - last PMWrapper tries to close PM.
        _isClosed = true;
        while (current != null) {
            current.close();
        }

        Collection c = _weakCache.values();
        for (Iterator it = c.iterator(); it.hasNext();) {
            StateManager sm = (StateManager)it.next();

            // RESOLVE - do we want to release all references in SM?
            // 1 of two calls below should be removed.

            // Only nullify PM reference in SM.
            //sm.setPersistenceManager(null);

            // Nullify all references in SM.
            sm.release(); // This requires 'release()' to be added to SM interface.
        }

        disconnectQueries();

        persistenceManagerFactory = null;
        _jta = null;

        _weakCache.clear();
        _txCache.clear();
        _flushedCache.clear();

        _flushedCache = null;
        _txCache = null;
        _weakCache = null;

        _store = null;
        _transaction = null;

        _exclusiveLockHolder = null;
    }

    /**
     * close the persistence manager
     */
    public void close() {

        acquireExclusiveLock();

        try {
            if (_jta != null) {
                // Called by the transaction completion - deregister.
                persistenceManagerFactory.releasePersistenceManager(this, _jta);
                _jta = null;
            }

            if (current != null && _transaction.getTransactionType() != TransactionImpl.CMT) {
                /*
                                  if (_transaction.getTransactionType() == TransactionImpl.BMT_JDO) {
                                  persistenceManagerFactory.releasePersistenceManager(this, _jta);
                                  _jta = null;
                                  }
                                */
                return;     // or throw an exception ???
            }

            if (_activeTransaction || _flushedCache.size() > 0) {
                throw new JDOException(I18NHelper.getMessage(messages,
                        "jdo.persistencemanagerimpl.close.activetransaction"));// NOI18N
            }

            forceClose();

        } finally {
            releaseExclusiveLock();
        }
    }


    /**
     * Returns transaction associated with this persistence manager
     * @return transaction	current transaction
     */
    public Transaction currentTransaction() {
        assertIsOpen();
        return _transaction;
    }


    /** Create a new Query with no elements.
     * @return a new Query instance with no elements.
     */
    public Query newQuery() {
        assertIsOpen();
        QueryImpl q = new QueryImpl(this);
        registerQuery(q);
        return q;
    }

    /** Create a new Query using elements from another Query.  The other Query
     * must have been created by the same JDO implementation.  It might be active
     * in a different PersistenceManager or might have been serialized and
     * restored.
     * @return the new Query
     * @param compiled another Query from the same JDO implementation
     */
    public Query newQuery(Object compiled) {
        assertIsOpen();
        QueryImpl q = new QueryImpl(this, compiled);
        registerQuery(q);
        return q;
    }

    /** Create a new Query specifying the Class of the results.
     * @param cls the Class of the results
     * @return the new Query
     */
    public Query newQuery(Class cls) {
        assertIsOpen();
        QueryImpl q = new QueryImpl(this, cls);
        registerQuery(q);
        return q;
    }

    /** Create a new Query with the Class of the results and candidate Collection.
     * specified.
     * @param cls the Class of results
     * @param cln the Collection of candidate instances
     * @return the new Query
     */
    public Query newQuery(Class cls, Collection cln) {
        assertIsOpen();
        QueryImpl q = new QueryImpl(this, cls, cln);
        registerQuery(q);
        return q;
    }

    /** Create a new Query with the Class of the results and Filter.
     * specified.
     * @param cls the Class of results
     * @param filter the Filter for candidate instances
     * @return the new Query
     */
    public Query newQuery(Class cls, String filter) {
        assertIsOpen();
        QueryImpl q = new QueryImpl(this, cls, filter);
        registerQuery(q);
        return q;
    }

    /** Create a new Query with the Class of the results, candidate Collection,
     * and Filter.
     * @param cls the Class of results
     * @param cln the Collection of candidate instances
     * @param filter the Filter for candidate instances
     * @return the new Query
     */
    public Query newQuery(Class cls, Collection cln, String filter) {
        assertIsOpen();
        QueryImpl q = new QueryImpl(this, cls, cln, filter);
        registerQuery(q);
        return q;
    }

    /** The PersistenceManager may manage a collection of instances in the data
     * store based on the class of the instances.  This method returns a
     * Collection of instances in the data store that might be iterated or
     * given to a Query as the Collection of candidate instances.
     * @param persistenceCapableClass Class of instances
     * @param subclasses whether to include instances of subclasses
     * @return a Collection of instances
     * @see #newQuery
     */
    public Collection getExtent(Class persistenceCapableClass,
                                boolean subclasses) {
        assertIsOpen();
        return new ExtentCollection(this, persistenceCapableClass, subclasses);
    }

    /** This method locates a persistent instance in the cache of instances
     * managed by this PersistenceManager.  If an instance with the same ObjectId
     * is found it is returned.  Otherwise, a new instance is created and
     * associated with the ObjectId.
     *
     * <P>If the instance does not exist in the data store, then this method will
     * not fail.  However, a request to access fields of the instance will
     * throw an exception.
     * @see #getObjectById(Object, boolean)
     * @param oid an ObjectId
     * @return the PersistenceCapable instance with the specified
     * ObjectId
     */
    public Object getObjectById(Object oid) {
        return getObjectById(oid, false);
    }

    /** This method locates a persistent instance in the cache of instances
     * managed by this <code>PersistenceManager.
     * The <code>getObjectByIdInternal method attempts
     * to find an instance in the cache with the specified JDO identity.
     * <P>If the PersistenceManager is unable to resolve the oid parameter
     * to an ObjectId instance, then it throws a <code>JDOUserException.
     * <P>If the validate flag is false, and there is already an instance in the
     * cache with the same JDO identity as the <code>oid parameter, then this method
     * returns it. There is no change made to the state of the returned
     * instance.
     * <P>If there is not an instance already in the cache with the same JDO
     * identity as the <code>oid parameter, then this method creates an instance
     * with the specified JDO identity and returns it. If there is no
     * transaction in progress, the returned instance will be hollow.
     * <P>If there is a transaction in progress, the returned instance will
     * persistent-nontransactional in an optimistic transaction, or persistent-clean in a
     * datastore transaction.
     * @return the <code>PersistenceCapable instance with the specified ObjectId
     * @param oid an ObjectId
     * @param validate if the existence of the instance is to be validated
     */
    public Object getObjectById(Object oid, boolean validate) {
        boolean debug = logger.isLoggable(Logger.FINEST);

        assertIsOpen();
        assertActiveTransaction(true);

        Object rc = null;

        if (debug) {
            Object[] items = new Object[] {oid, this,_jta};
            logger.finest("sqlstore.persistencemgr.getbyobjid", items); // NOI18N
        }

        if (oid == null)
            return null;

        StateManager sm = lookupObjectById(oid, null);
        rc = sm.getPersistent();
        if (!JDOHelper.isTransactional(rc)) {

            // Instance was not found in _weakCache, or the found instance is
            // non transactional.  Check the version consistency cache.
            boolean foundInstance = initializeFromVersionConsistencyCache(sm);

            if (validate && !foundInstance) {

                // Not found in the cache, or non transactional.
                try {
                    sm.reload();

                } catch (JDOException e) {
                    if (!sm.isValid()) {
                        // This StateManager had never been used before.
                        deregisterInstance(oid);
                        sm.release();
                    }

                    throw e;
                } catch (Exception e) {
                    throw new JDOUserException(I18NHelper.getMessage(messages,
                       "jdo.persistencemanagerimpl.fetchinstance.none"), e);// NOI18N
                }
            }
        }

        sm.setValid();
        return rc;
    }

    /**
     * Called internally by <code>RetrieveDesc to lookup an instance
     * in the cache, or prepare new instance to be populated with values from the datastore.
     * @return the <code>StateManager instance with the specified ObjectId
     * @param oid an ObjectId
     * @param pcClass the Class type of the PersistenceCapable instance to be associated
     * with this StateManager.
     */
    public StateManager findOrCreateStateManager(Object oid, Class pcClass) {
        return lookupObjectById(oid, pcClass);
    }

    /** This is the actual implementation of the #getObjectById(Object oid, validate) and
     * #getObjectByIdInternal(Object oid, Class pcClass).
     * @param oid an ObjectId
     * @param classType the Class type of the returned object or null if not known.
     */
    private StateManager lookupObjectById(Object oid, Class classType) {
        StateManager sm = null;

        // Check the _weakCache for the instance
        try {
            acquireCacheLock();

            sm = (StateManager)_weakCache.get(oid);
            if (sm == null) {
                boolean external = false;
                // Do NOT look in DB, but create a Hollow instance:
                if (classType == null) {
                    classType = loadClassForOid(oid);

                    if (classType == null) {
                        // Class not found, report an error
                        throw new JDOUserException(I18NHelper.getMessage(messages,
                                "jdo.persistencemanagerimpl.getobjectbyid.nometadata"), // NOI18N
                                new Object[]{oid});
                    }
                    external = true;
                }

                try {
                    // create new instance and register it
                    sm = createStateManager(classType);
                    if (external) {
                        // oid needs to be cloned for extenral cases
                        // as the user might modify oid
                        oid = internalCloneOid(oid, sm);
                    }
                    sm.setObjectId(oid);
                    setKeyFields(sm);

                    if (external) {
                        sm.initialize(false);
                    } else {
                        // put it in the weak cache only as it is Hollow.
                        _weakCache.put(oid, sm);
                    }
                } catch (JDOException e) {
                    throw e;
                } catch (Exception e) {
                    throw new JDOUserException(I18NHelper.getMessage(messages,
                            "jdo.persistencemanagerimpl.fetchinstance.none"), e);// NOI18N
                }
            }
        } finally {
            releaseCacheLock();
        }

        return sm;
    }

    /**
     * Create a StateManager.
     * @param classType Class of the PersistenceCapable.
     */
    private StateManager createStateManager(Class classType) {
        StateManager rc = _store.getStateManager(classType);
        newInstance(rc);

        return rc;
    }

    /** The ObjectId returned by this method represents the JDO identity of
     * the instance.  The ObjectId is a copy (clone) of the internal state
     * of the instance, and changing it does not affect the JDO identity of
     * the instance.
     * Delegates actual execution to the internal method.
     * @param pc the PersistenceCapable instance
     * @return the ObjectId of the instance
     */
    public Object getObjectId(Object pc) {
        boolean debug = logger.isLoggable(Logger.FINEST);

        assertIsOpen();
        assertActiveTransaction(true);

        if (debug) {
            Object[] items = new Object[] {Thread.currentThread(),pc, this, _jta};
            logger.finest("sqlstore.persistencemgr.getobjid",items); // NOI18N
        }

        try {
            assertPersistenceCapable(pc);
        } catch (Exception e) {
            if (debug) {
                Object[] items = new Object[] {pc, this};
                logger.finest("sqlstore.persistencemgr.getobjid.notpc",items); // NOI18N
            }

            return null;
        }

        StateManager sm = ((PersistenceCapable)pc).jdoGetStateManager();
        if (sm == null) {
            // Not persistent
            return null;

        } else if (sm.getPersistenceManagerInternal() != this) {
            if (debug) {
                Object[] items = new Object[] {pc, this, _jta};
                logger.finest("sqlstore.persistencemgr.getobjid.notpm",items); // NOI18N
            }

            return null;
        }

        return internalGetObjectId(sm);
    }

    /** This method is used to get a PersistenceCapable instance
     * representing the same data store object as the parameter, that is valid
     * for this PersistenceManager.
     * @param pc a PersistenceCapable instance
     * @return the PersistenceCapable instance representing the
     * same data store object
     */
    public Object getTransactionalInstance(Object pc) {
        assertIsOpen();
        assertActiveTransaction(false);
        if (!(pc instanceof PersistenceCapable)) {
            return pc;
        }

        PersistenceCapable mypc = (PersistenceCapable) pc;

        // The PC.jdoGetPersistenceManager() returns PersistenceManagerWrapper:
        PersistenceManagerWrapper pmw = (PersistenceManagerWrapper) mypc.jdoGetPersistenceManager();
        PersistenceManagerImpl pm = (PersistenceManagerImpl) pmw.getPersistenceManager();

        if (pm == null || pm == this) {
            return pc;
        }

        return getObjectById(pm.internalGetObjectId(mypc.jdoGetStateManager()));
    }

    /** Make the transient instance persistent in this PersistenceManager.
     * This method must be called in an active transaction.
     * The PersistenceManager assigns an ObjectId to the instance and
     * transitions it to persistent-new.
     * The instance will be managed in the Extent associated with its Class.
     * The instance will be put into the data store at commit.
     * @param pc a transient instance of a Class that implements
     * PersistenceCapable
     */
    public void makePersistent(Object pc) {
        boolean debug = logger.isLoggable(Logger.FINEST);

        if (debug)
            {
            Object[] items = new Object[] {Thread.currentThread(), pc, this, _jta};
            logger.finest("sqlstore.persistencemgr.makepersistent",items); // NOI18N
            }

        if (pc == null)
            return;		// ignore

        acquireShareLock();
        try {
            assertIsOpen();
            assertActiveTransaction(false);
            assertPersistenceCapable(pc);
            internalMakePersistent((PersistenceCapable) pc);
            if (debug)
                {
                 Object[] items = new Object[] {pc, this, _jta};
                 logger.finest("sqlstore.persistencemgr.makepersistent.done",items); // NOI18N
                }

        } finally {
            releaseShareLock();
        }
    }

    /** Make an array of instances persistent.
     * @param pcs an array of transient instances
     * @see #makePersistent(Object pc)
     */
    public void makePersistent(Object[] pcs) {
        if (pcs == null)
            return;		// ignore

        for (int i = 0; i < pcs.length; i++) {
            makePersistent(pcs[i]);
        }
    }

    public void makePersistent(Collection pcs) {
        if (pcs == null)
            return;		// ignore

        makePersistent(pcs.toArray());
    }

    public void deletePersistent(Object pc) {
        if (pc == null)
            return;		// ignore

        acquireShareLock();

        try {
            assertIsOpen();
            assertActiveTransaction(false);
            assertPersistenceCapable(pc);
            internalDeletePersistent((PersistenceCapable) pc);
        } finally {
            releaseShareLock();
        }
    }

    public void deletePersistent(Object[] pcs) {
        if (pcs == null)
            return;		// ignore

        for (int i = 0; i < pcs.length; i++) {
            deletePersistent(pcs[i]);
        }
    }

    public void deletePersistent(Collection pcs) {
        if (pcs == null)
            return;		// ignore

        deletePersistent(pcs.toArray());
    }


    /** This method returns the PersistenceManagerFactory used to create
     * this PersistenceManager.  It returns null if this instance was
     * created via a constructor.
     * @return the PersistenceManagerFactory that created
     * this PersistenceManager
     */
    public com.sun.jdo.api.persistence.support.PersistenceManagerFactory getPersistenceManagerFactory() {
        return persistenceManagerFactory;
    }

    void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
        if (persistenceManagerFactory == null)
            persistenceManagerFactory = pmf;
    }

    /** The application can manage the PersistenceManager instances
     * more easily by having an application object associated with each
     * PersistenceManager instance.
     * @param o the user instance to be remembered by the PersistenceManager
     * @see #getUserObject
     */
    public void setUserObject(Object o) {
        this._userObject = o;
    }

    /** The application can manage the PersistenceManager instances
     * more easily by having an application object associated with each
     * PersistenceManager instance.
     * @return the user object associated with this PersistenceManager
     * @see #setUserObject
     */
    public Object getUserObject() {
        return _userObject;
    }

    /** The JDO vendor might store certain non-operational properties and
     * make those properties available to applications (for troubleshooting).
     *
     * <P>Standard properties include:
     * <li>VendorName
     * <li>VersionNumber
     * @return the Properties of this PersistenceManager
     */
    public Properties getProperties() {
        if (_properties == null) {
            _properties = RuntimeVersion.getVendorProperties(
                    "/com/sun/jdo/spi/persistence/support/sqlstore/sys.properties");// NOI18N
        }
        return _properties;
    }

    /**
     * Returns the boolean value of the supersedeDeletedInstance flag
     * for this PersistenceManager. If set to true, deleted instances are
     * allowed to be replaced with persistent-new instances with the equal
     * Object Id.
     * @return      boolean supersedeDeletedInstance flag
     */
    public boolean getSupersedeDeletedInstance () {
        return _supersedeDeletedInstance;
    }


    /**
     * Sets the supersedeDeletedInstance flag for this PersistenceManager.
     * @param flag          boolean supersedeDeletedInstance flag
     */
    public void setSupersedeDeletedInstance (boolean flag) {
        // RESOLVE: synchronization
        _supersedeDeletedInstance = flag;
    }

    /**
     * Returns the boolean value of the requireCopyObjectId flag
     * for this PersistenceManager. If set to false, the PersistenceManager
     * does not create a copy of an ObjectId for <code>PersistenceManager.getObjectId(Object pc)
     * and <code>PersistenceManager.getObjectById(Object oid) requests.
     *
     * @see PersistenceManager#getObjectId(Object pc)
     * @see PersistenceManager#getObjectById(Object oid)
     * @return      boolean requireCopyObjectId flag
     */
    public boolean getRequireCopyObjectId() {
        return _requireCopyObjectId;
    }


    /**
     * Sets the requireCopyObjectId flag for this PersistenceManager.
     * If set to false, the PersistenceManager will not create a copy of
     * an ObjectId for <code>PersistenceManager.getObjectId(Object pc)
     * and <code>PersistenceManager.getObjectById(Object oid) requests.
     *
     * @see PersistenceManager#getObjectId(Object pc)
     * @see PersistenceManager#getObjectById(Object oid)
     * @param flag          boolean requireCopyObjectId flag
     */
    public void setRequireCopyObjectId (boolean flag) {
        // RESOLVE: synchronization
        _requireCopyObjectId = flag;
    }

    /**
     * Returns the boolean value of the requireTrackedSCO flag
     * for this PersistenceManager. If set to false, this PersistenceManager
     * will not create tracked SCO instances for
     * new persistent instances at commit with retainValues set to true
     * and while retrieving data from a datastore.
     *
     * @return      boolean requireTrackedSCO flag
     */
    public boolean getRequireTrackedSCO() {
        return _requireTrackedSCO;
    }

    /**
     * Sets the requireTrackedSCO flag for this PersistenceManager.
     * If set to false, this PersistenceManager will not create tracked
     * SCO instances for new persistent instances at commit with retainValues
     * set to true and while retrieving data from a datastore.
     *
     * @param flag          boolean requireTrackedSCO flag
     */
    public void setRequireTrackedSCO (boolean flag) {
        // RESOLVE: synchronization
        _requireTrackedSCO = flag;
    }

    /** In order for the application to construct instance of the ObjectId class
     * it needs to know the class being used by the JDO implementation.
     * @param cls the PersistenceCapable Class
     * @return the Class of the ObjectId of the parameter
     */
    public Class getObjectIdClass(Class cls) {
        PersistenceConfig config = loadPersistenceConfig(cls);
        return config.getOidClass();
    }

    /**
     * Returns a new instance of the object defined by the given
     * StateManager
     * @param 	sm	StateManager
     * @return	new instance of the object
     */
    public Object newInstance(StateManager sm) {
        Object o = null;

        PersistenceConfig config = sm.getPersistenceConfig();

        if (config == null) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.newinstance.badsm"));// NOI18N
        }

        Constructor constr = config.getConstructor();
        try {
            if (constr != null) {
                o = constr.newInstance(new Object[]{sm});

                // Initalize the state manager to reference this pm and the newly created instance
                sm.setPersistenceManager(this);
                sm.setPersistent(o);
            }
        } catch (Exception e) {
            throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.assertpersistencecapable.error", // NOI18N
                    config.getPersistenceCapableClass().getName()), e);
        }

        return o;
    }

    /**
     * Executes the given retrieve descriptor. The result
     * is a collection unless an aggregate query was specified.
     * In most cases the query result is a collection of
     * persistent objects. In case of a projection
     * on a local field the collection holds objects of that
     * type. For aggregate queries the result is a
     * single object, which type was defined by the caller.
     *
     * @param action The retrieve descriptor.
     * @param parameters The input parameters for the query.
     * @return A collection of (persistent) objects unless
     * an aggregate query was specified.
     */
    public Object retrieve(RetrieveDesc action, ValueFetcher parameters)
    {
        acquireShareLock();

        try {
            assertActiveTransaction(true);
            return _store.retrieve(this, action, parameters);
        } finally {
            releaseShareLock();
        }
    }

    /**
     * Executes the given retrieve descriptor. The result
     * is a collection unless an aggregate query was specified.
     * In most cases the query result is a collection of
     * persistent objects. In case of a projection
     * on a local field the collection holds objects of that
     * type. For aggregate queries the result is a
     * single object, which type was defined by the caller.
     *
     * @param action The retrieve descriptor.
     * @return A collection of (persistent) objects unless
     * an aggregate query was specified.
     */
    public Object retrieve(RetrieveDesc action) {
        return retrieve(action, null);
    }

    /**
     * Return a RetrieveDesc given a Class object.
     */
    public RetrieveDesc getRetrieveDesc(Class classType) {
        acquireShareLock();

        try {
            loadPersistenceConfig(classType);
            return _store.getRetrieveDesc(classType);
        } finally {
            releaseShareLock();
        }
    }

    /**
     * Return a RetrieveDesc for a foreign field (relationship) given the
     * Class object for the parent class.
     */
    public RetrieveDesc getRetrieveDesc(String fieldName, Class classType) {
        acquireShareLock();

        try {
            loadPersistenceConfig(classType);
            return _store.getRetrieveDesc(fieldName, classType);
        } finally {
            releaseShareLock();
        }
    }


    /**
     * Register instance in the weak cache only. Used to restore persistent instance
     * at the rollback if it was replaced during transaction execution with another
     * instance with the same object Id.
     */
    public void registerInstance(StateManager sm, Object oid) {
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug)
            {
            Object[] items = new Object[] {Thread.currentThread(), oid, this, _jta};
            logger.finest("sqlstore.persistencemgr.registerinstance",items); // NOI18N
            }

        try {
            acquireCacheLock();
            if (debug)
                logger.finest("sqlstore.persistencemgr.registerinstancein_wkc"); // NOI18N

            _weakCache.put(oid, sm);

            if (sm.needsRegisterWithVersionConsistencyCache()) {
                addToVersionConsistencyCache(sm);
            }
        } finally {
            releaseCacheLock();
        }
    }

    /**
     * Register instance in the transactional cache
     */
    public void registerInstance(StateManager sm, Object oid,
                boolean throwDuplicateException,
                boolean forceRegister) {
        if (oid == null) {
            oid = sm.getObjectId();
        }

        boolean debug = logger.isLoggable();
        if (debug) {
            Object[] items = new Object[] {Thread.currentThread(), oid, sm, this, _jta};
            logger.finest("sqlstore.persistencemgr.registerinstance",items); // NOI18N
        }

        //
        // register in all caches
        // We do explicit synchronization here using the cacheMutex. Note that for
        // performance reason, we only synchronize in the case where the instance
        // is not already in the cache.
        //
        try {
            acquireCacheLock();
            if (!_weakCache.containsKey(oid)) {
                if (debug)
                    logger.finest("sqlstore.persistencemgr.registerinstancein_wkc"); // NOI18N

                _weakCache.put(oid, sm);
            } else if (throwDuplicateException) {
                StateManager old = (StateManager)_weakCache.get(oid);
                if (_supersedeDeletedInstance && old.isDeleted()) {

                if (debug)
                    logger.finer(I18NHelper.getMessage(messages,
                        "sqlstore.persistencemgr.replacingdeletedinstance", oid)); // NOI18N

                    old.markNotRegistered();
                    old.markVerifyAtDeregister();
                    sm.markVerifyAtDeregister();
                    sm.markReplacement();

                    // Add the dependency management, so that delete happens
                    // before the insert. This operation registers the new instance.
                    old.addDependency(sm);

                    // Now we need to replace the old StateManager with the new
                    // in the _weakCache, because of the StateManager's dependency
                    // process.
                    _weakCache.put(oid, sm);

                    // Do not proceed as addDependency registered instance already.
                    return;

                } else {
                    throw new JDODuplicateObjectIdException(I18NHelper.getMessage(messages,
                        "jdo.persistencemanagerimpl.internalmakepersistent.dups"), // NOI18N
                        new Object[]{sm.getPersistent()});
                }
            }

            if (_activeTransaction && (sm.isTransactional() || forceRegister)) {
                if (debug) {
                    Object[] items = new Object[] {oid,sm.getPersistent(),this, _jta};
                    logger.finest("sqlstore.persistencemgr.registerinstancein_txc",items); // NOI18N
                }

                // Need to be carefull not to request registerInstance twice
                // for a dirty instance.
                if (sm.isDirty()) {
                    _txCache.add(sm);
                }

                // _flushedCache is a Set so it cannot have duplicates.
                _flushedCache.add(sm);

                if (sm.needsRegisterWithVersionConsistencyCache()) {
                    addToVersionConsistencyCache(sm);
                }
            }

        } finally {
            releaseCacheLock();
        }
    }

    public void deregisterInstance(Object oid) {
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug) {
            Object[] items = new Object[] {oid,this,_jta};
            logger.finest("sqlstore.persistencemgr.deregisterinstance",items); // NOI18N
        }

        if (oid != null) {
            try {
                acquireCacheLock();
                StateManager sm = (StateManager) _weakCache.remove(oid);
                removeFromCaches(sm);
            } finally {
                releaseCacheLock();
            }
        }
    }

    public void deregisterInstance(Object oid, StateManager sm) {
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug) {
            Object[] items = new Object[] {oid,this,_jta};
            logger.finest("sqlstore.persistencemgr.deregisterinstance.verify",items); // NOI18N
        }

        try {
            acquireCacheLock();
            Object known = _weakCache.get(oid);
            if (known == sm) {
                //deregister the instance from weak cache only if it is registered.
                 _weakCache.remove(oid);
                if (debug)
                    logger.finest("sqlstore.persistencemgr.deregisterinstance.verified"); // NOI18N
            }

            removeFromCaches(sm);
        } finally {
            releaseCacheLock();
        }
    }

    /**
     * If a transaction is active, removes the given StateManger from all
     * caches, otherwise just from the Version Consistency cache.
     * @param sm StateManager to remove
     */
    private void removeFromCaches(StateManager sm) {
        if (sm != null) {
            if (_activeTransaction) {
                // RESOLVE: Duplicates are not removed!
                _txCache.remove(sm);
                _flushedCache.remove(sm);
            }
            removeFromVersionConsistencyCache(sm);
        }
    }


    /**
     * Called by Transaction commit(). Flushes dirty instances to the store.
     * Clean instances registered for Version Consistency are verified with
     * the store.
     */
    public void beforeCompletion() {
        if (logger.isLoggable(Logger.FINEST)) {
            logger.finest("sqlstore.persistencemgr.beforecompletion"); // NOI18N
        }

        assertIsOpen();
        assertActiveTransaction(false);
        _insideCommit = true;

        prepareToUpdate();

        try {
            flushTxCache();

            // Verify version consistent instances on commit only.
            if (!_insideFlush) {
                verifyFlushedCache();
            }
        } catch (JDODataStoreException ex) {

            // If an instance failed to flush, remember to cleanup the Version
            // Consistency cache (see afterCompletion).
            cleanupVersionConsistencyCache = true;
            throw ex;
        }
    }

    /**
     * Calls the state manager's prepare to update phases I-III.
     * Phase II and III are called during commit processing only.
     *
     * @see StateManager#prepareToUpdatePhaseI
     * @see StateManager#prepareToUpdatePhaseII
     * @see StateManager#prepareToUpdatePhaseIII
     */
    private void prepareToUpdate() {
        for (int i = 0; i < _txCache.size(); i++) {
            StateManager sm = (StateManager)_txCache.get(i);
            // NOTE: prepareToUpdatePhaseI has the side-effect of adding more objects
            // to the transaction cache.

            sm.prepareToUpdatePhaseI();
        }

        // We only do phase 2 and 3 during commit only.
        if (!_insideFlush) {
            HashSet phase3sms = new HashSet();

            for (Iterator iter = _flushedCache.iterator(); iter.hasNext(); ) {
                StateManager sm = (StateManager)iter.next();
                // NOTE: prepareToUpdatePhaseII has the side-effect of adding state managers
                // to the phase3sms HashSet which need to have prepareToUpdatePhaseIII()
                // called on them

                sm.prepareToUpdatePhaseII(phase3sms);
            }

            Iterator iter = phase3sms.iterator();

            // phase3sms should contain all the non-reachable autopersistence instance.
            // We need to call prepareToUpdatePhaseIII on them to make sure we roll
            // back any changes that may have been flushed to the datastore.

            while (iter.hasNext()) {
                StateManager sm = (StateManager) iter.next();
                sm.prepareToUpdatePhaseIII();
            }
        }
    }

    /**
     * Writes the instances from the transactional cache to the store.
     * The transactional cache contains modified instances only.
     *
     * @exception JDOUserException if instances can't be flushed
     *  because of circular dependencies.
     */
    private void flushTxCache() {
        List err = flushToDataStore(_txCache);

        // Try to resolve dependencies.
        if (err != null && err.size() > 0) {
            Iterator iter = err.iterator();
            while (iter.hasNext()) {
                ((StateManager) iter.next()).resolveDependencies();
            }
            // Second flush.
            err = flushToDataStore(err);
        }

        if (err != null && err.size() > 0) {
            _transaction.setRollbackOnly();
            throw new JDOUserException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.notprocessed"), // NOI18N
                    toPCArray(err));
        }
    }

    /**
     * Loops through flushed cache and calls PersistentStore.verifyPersistent()
     * on each instance. The flushed cache contains all instances accessed in
     * this transaction. To prevent database deadlocks, it's important to
     * iterate the flushed cache in the order the instances were used in the
     * transaction, as garanteed by {@link LinkedHashSet}.
     *
     * @exception JDODataStoreException if a cached instance has been updated
     * from outside.
     */
    private void verifyFlushedCache() {
        Iterator iter = _flushedCache.iterator();

        while (iter.hasNext()) {
            StateManager sm = (StateManager)iter.next();

            if (sm.hasVersionConsistency() && !sm.verifyPersistent()) {
                Object [] items = { sm.getPersistent() };

                // The instance failed the verification with the data store.
                sm.setVerificationFailed();
                throw new JDODataStoreException(I18NHelper.getMessage(messages,
                        "jdo.persistencemanagerimpl.verificationfailed"), items);  // NOI18N
            }
        }
    }

    /**
     * Writes the instances in <code>flushList to the data store.
     * Loops through the list and calls StateManager.updatePersistent()
     * on each instance.
     *
     * @param flushList List of state managers to be flushed.
     * @return List containing state managers not flushed
     *   because of unresolved dependencies, null if all
     *   instances could be processed.
     */
    static private List flushToDataStore(List flushList) {
        int size = flushList.size();
        List errorList = null;

        // The connection initialisation is not neccessary. There
        // are two conditions in TransactionImpl assuring connections
        // are not released in releaseConnections,
        // even if the internal reference count on the connection is 0:
        // - we are in the commit processing
        // - in a non managed environment, connections aquired for queries in pessimistic
        // transactions are not released until commit
        // Please refer to TransactionImpl.releaseConnection
        for (int i = 0; i < size; i++) {
            StateManager sm = (StateManager)flushList.get(i);
            StateManager smNext =
                (i+1 < size)? (StateManager)flushList.get(i+1) : null;
            sm.updatePersistent(smNext);
        }

        for (int i = 0; i < size; i++) {
            StateManager sm = (StateManager)flushList.get(i);
            if (!sm.isProcessed()) {
                if (errorList == null) {
                    errorList = new ArrayList();
                }

                // Dependencies have not been resolved.
                errorList.add(sm);
            }
        }
        return errorList;
    }

    /**
     * Converts the list <code>smList of state managers into
     * an Array of persistence capable instances.
     *
     * @param smList List of state managers.
     * @return Array of persistence capable instances.
     */
    static private Object[] toPCArray(List smList) {
        final int size = smList.size();
        if (size > 0) {
            List pcList = new ArrayList(size);

            for (int i = 0; i < size; i++) {
                StateManager sm = (StateManager)smList.get(i);
                pcList.add(sm.getPersistent());
            }
            return pcList.toArray();
        }
        return null;
    }

    /**
     * Called by Transaction commit() or rollback()
     * cleans up transactional cache
     * @param	status		javax.transaction.Status
     */
    public void afterCompletion(int status) {
        assertIsOpen();
        _insideCommit = true;
        boolean abort = ((status == Status.STATUS_ROLLEDBACK) ||
                (status == Status.STATUS_ROLLING_BACK) ||
                (status == Status.STATUS_MARKED_ROLLBACK));
        boolean debug = false;
        debug = logger.isLoggable(Logger.FINEST);
        if (debug)
            logger.finest("sqlstore.persistencemgr.aftercompletion",new Boolean(abort)); // NOI18N

        boolean retainValues = _transaction.getRetainValues();

        for (Iterator iter = _flushedCache.iterator(); iter.hasNext(); ) {
            StateManager sm = (StateManager)iter.next();
            if (debug)
                logger.finest("sqlstore.persistencemgr.aftercompletion.process",sm.getObjectId()); // NOI18N

            if (abort) {
                rollback(sm, retainValues);
            } else {
                commit(sm, retainValues);
            }
        }

        // Clear the transactional caches
        _txCache.clear();
        _flushedCache.clear();

        _insideCommit = false;
        cleanupVersionConsistencyCache = false;
    }

    /**
     * Commits the given StateManager instance after first adding it to the
     * Version Consistency cache (if necessary).
     * @param sm Instance to be comitted and possibly added to the cache.
     * @param retainValues as per the current transaction.
     */
    private void commit(StateManager sm, boolean retainValues) {

        if (sm.needsUpdateInVersionConsistencyCache()) {
            StateManager nonTxSM = lookupFromVersionConsistencyCache(sm);

            if (null != nonTxSM) {
                nonTxSM.copyFields(sm);
            } else {
                addToVersionConsistencyCache(sm);
            }
        }
        sm.commit(retainValues);
    }

    /**
     * Does a rollback on the given StateManager instance after first removing
     * it from the Version Consistency cache (if necessary).
     * @param sm Instance to be rolled back and possibly removed from the
     * cache.
     * @param retainValues as per the current transaction.
     */
    private void rollback(StateManager sm, boolean retainValues) {
        if (cleanupVersionConsistencyCache && sm.isVerificationFailed()) {
            removeFromVersionConsistencyCache(sm);
        }
        sm.rollback(retainValues);
    }

    /**
     * Adds given instance to the Version Consistency cache, if the
     * instance supports Version Consistency.
     * @param sm Instance to be added to the cache.
     * @return If an instance was already in the cache for the given
     * <code>sm, it is returned; otherwise null.
     */
    private StateManager addToVersionConsistencyCache(StateManager sm) {
        StateManager rc = null;

        if (null != sm && sm.hasVersionConsistency()) {
            Class pcType = sm.getPersistent().getClass();
            Object oid = sm.getObjectId();
            VersionConsistencyCache vcCache =
                    persistenceManagerFactory.getVersionConsistencyCache();

            if (vcCache.get(pcType, oid) == null) {
                StateManager nonTxSM = createStateManager(pcType);

                nonTxSM.copyFields(sm);
                nonTxSM.setPersistenceManager(null); // Disconnect SM from PM

                rc = vcCache.put(pcType, oid, nonTxSM);
            }
        }
        return rc;
    }

    /**
     * Removes given instance from the Version Consistency cache, if the
     * instance supports Version Consistency.
     * @param sm Instance to be removed from the cache.
     * @return If an instance was already in the cache for the given
     * <code>sm, it is returned; otherwise null.
     */
    private StateManager removeFromVersionConsistencyCache(StateManager sm) {
        StateManager rc = null;

        if (null != sm && sm.hasVersionConsistency()) {
            Class pcType = sm.getPersistent().getClass();
            Object oid = sm.getObjectId();
            VersionConsistencyCache vcCache =
                    persistenceManagerFactory.getVersionConsistencyCache();
            rc = vcCache.remove(pcType, oid);

            if (null == rc) {
                // XXX should not happen; throw exception?
            }
        }
        return rc;
    }

    /**
     * @inheritDoc
     */
    public boolean initializeFromVersionConsistencyCache(StateManager sm) {
        boolean rc = false;
        StateManager nonTxSM = lookupFromVersionConsistencyCache(sm);

        if (null != nonTxSM) {
            rc = true;

            // Synchronize so that no other threads change/access the
            // cache'd nonTxSm while copying fields.
            synchronized (nonTxSM) {
                sm.copyFields(nonTxSM);
            }
            sm.initialize(true);
        }
        return rc;
    }

    /**
     * Looks up given instance from the Version Consistency cache, if the
     * instance supports Version Consistency.
     * @param sm Instance to be looked up from the cache.
     * @return If an instance was already in the cache for the given
     * <code>sm, it is returned; otherwise null.
     */
    private StateManager lookupFromVersionConsistencyCache(StateManager sm) {
        StateManager rc = null;

        if (null != sm && sm.hasVersionConsistency()) {
            Class pcType = sm.getPersistent().getClass();
            Object oid = sm.getObjectId();
            VersionConsistencyCache vcCache =
                persistenceManagerFactory.getVersionConsistencyCache();

            rc = vcCache.get(pcType, oid);
        }
        return rc;
    }

    public void setStateManager(Object pc, StateManager sm) {
        if (pc instanceof PersistenceCapable) {
            ((PersistenceCapable) pc).jdoSetStateManager(sm);
        }

        //RESOLVE: Otherwise, should throw an exception.
    }


    public void setFlags(Object pc, byte flags) {
        if (pc instanceof PersistenceCapable) {
            ((PersistenceCapable) pc).jdoSetFlags(flags);
        }

        //RESOLVE: Otherwise, should throw an exception.
    }

    public byte getFlags(Object pc) {
        if (pc instanceof PersistenceCapable) {
            return ((PersistenceCapable) pc).jdoGetFlags();
        }

        return 0;
        //RESOLVE: Otherwise, should throw an exception.
    }

    public StateManager getStateManager(Object pc) {
        if (pc instanceof PersistenceCapable) {
            return ((PersistenceCapable) pc).jdoGetStateManager();
        }

        return null;
        //RESOLVE: Otherwise, should throw an exception.
    }


    public void setField(Object o, int fieldNumber, Object value) {
        if (o instanceof PersistenceCapable) {
            PersistenceCapable pc = (PersistenceCapable) o;
            pc.jdoSetField(fieldNumber, value);
        }

        //RESOLVE: Otherwise, should throw an exception.
    }

    public Object getField(Object pc, int fieldNumber) {
        if (pc instanceof PersistenceCapable) {
            return ((PersistenceCapable) pc).jdoGetField(fieldNumber);
        }

        //RESOLVE: Otherwise, should throw an exception.
        return null;
    }

    public void clearFields(Object pc) {
        if (pc instanceof PersistenceCapable) {
            ((PersistenceCapable) pc).jdoClear();
        }
    }

    /**
     * Returns a new Second Class Object instance of the type specified,
     * with the owner and field name to notify upon changes to the value
     * of any of its fields. If a collection class is created, then the
     * class does not restrict the element types, and allows nulls to be added as elements.
     *
     * @param type Class of the new SCO instance
     * @param owner the owner to notify upon changes
     * @param fieldName the field to notify upon changes
     * @return the object of the class type
     */
    public Object newSCOInstance(Class type, Object owner, String fieldName) {
        Object obj = null;

        if (Collection.class.isAssignableFrom(type)) {
            obj = this.newCollectionInstanceInternal(type, owner, fieldName, null, true, 0);
        } else {
            obj = newSCOInstanceInternal(type, owner, fieldName);

        }

        this.replaceSCO(fieldName, owner, obj);


        return obj;
    }

    /**
     * Called by newSCOInstance from the public interface or internally
     * by the runtime
     * Will not result in marking field as dirty
     *
     * Returns a new Second Class Object instance of the type specified,
     * @param type Class of the new SCO instance
     * @param owner the owner to notify upon changes
     * @param fieldName the field to notify upon changes
     * @return the object of the class type
     */
    public Object newSCOInstanceInternal(Class type, Object owner, String fieldName) {

        Object obj = null;

        if (type == java.sql.Date.class
                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlDate.class) {
            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlDate(owner, fieldName);

        } else if (type == java.sql.Time.class
                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTime.class) {
            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTime(owner, fieldName);

        } else if (type == java.sql.Timestamp.class
                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTimestamp.class) {
            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTimestamp(owner, fieldName);

        } else if (type == com.sun.jdo.spi.persistence.support.sqlstore.sco.Date.class
                || Date.class.isAssignableFrom(type)) {
            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.Date(owner, fieldName);

        } else {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.newscoinstance.wrongclass", // NOI18N
                    type.getName()));
        }

        return obj;
    }


    /**
     * Returns a new Collection instance of the type specified, with the
     * owner and field name to notify upon changes to the value of any of its fields.
     * The collection class restricts the element types allowed to the elementType or
     * instances assignable to the elementType, and allows nulls to be added as
     * elements based on the setting of allowNulls. The Collection has an initial size
     * as specified by the initialSize parameter.
     * We choose to use HashSet as a default collection (no specific type is chosen)
     * because we do not support duplicate objects in DB
     *
     * @param type Class of the new SCO instance
     * @param owner the owner to notify upon changes
     * @param fieldName the field to notify upon changes
     * @param elementType the element types allowed
     * @param allowNulls true if allowed
     * @param initialSize initial size of the Collection
     * @return the object of the class type
     */
    public Object newCollectionInstance(Class type, Object owner, String fieldName,
                                        Class elementType, boolean allowNulls, int initialSize) {
        Object obj = newCollectionInstanceInternal(type, owner, fieldName,
                elementType, allowNulls, initialSize);

        this.replaceSCO(fieldName, owner, obj);

        return obj;
    }

    /**
     * Called by newCollectionInstance from the public interface or internally
     * by the runtime
     * Will not result in marking field as dirty
     *
     * @see #newCollectionInstance for more information
     * @param type Class of the new SCO instance
     * @param owner the owner to notify upon changes
     * @param fieldName the field to notify upon changes
     * @param elementType the element types allowed
     * @param allowNulls true if allowed
     * @param initialSize initial size of the Collection
     * @return the object of the class type
     */
    public Object newCollectionInstanceInternal(Class type, Object owner, String fieldName,
                                                Class elementType, boolean allowNulls, int initialSize) {
        Object obj = null;

        // Make sure that the order of type comparison will go from
        // narrow to wide:
        if (type == HashSet.class
                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet.class) {
            if (initialSize == 0)
                initialSize = 101;
            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet(
                owner, fieldName, elementType, allowNulls, initialSize);
/*
        } else if (type == Vector.class
                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.Vector.class) {
            newType = com.sun.jdo.spi.persistence.support.sqlstore.sco.Vector.class;
        } else if (type == ArrayList.class
                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.ArrayList.class) {
            newType = com.sun.jdo.spi.persistence.support.sqlstore.sco.ArrayList.class;
        } else if (List.class.isAssignableFrom(type)) {
            newType = com.sun.jdo.spi.persistence.support.sqlstore.sco.Vector.class;
*/
        } else if (Set.class.isAssignableFrom(type)) {
            if (initialSize == 0)
                initialSize = 101;
            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet(
                owner, fieldName, elementType, allowNulls, initialSize);

        } else if (Collection.class.isAssignableFrom(type)) {
            // We choose to use HashSet as a default collection
            // because we do not support duplicate objects in DB
            if (initialSize == 0)
                initialSize = 101;
            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet(
                owner, fieldName, elementType, allowNulls, initialSize);

        } else {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.newscoinstance.wrongclass", // NOI18N
                    type.getName()));
        }
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug)
            logger.finest("sqlstore.persistencemgr.newcollection",obj.getClass()); // NOI18N

        return obj;
    }

    /**
     * Called by Query to flush updates to the database
     * in pessimistic transaction. Calls internaly beforeCompletion() to do actual
     * flush
     * @see #beforeCompletion()
     */
    public void internalFlush() {
        acquireExclusiveLock();

        try {
            //
            // Only flush if we are not in optimistic transaction.
            //
            if (_optimistic == false) {
                //
                // Note: no need to lock _cacheLock because we already have
                // exclusive using of the _weakCache and _txCache due to
                // the exclusive lock.
                //

                _insideFlush = true;
                beforeCompletion();
                _insideCommit = false;

                int status = _transaction.getStatus();

                if ((status == Status.STATUS_ROLLEDBACK) ||
                        (status == Status.STATUS_ROLLING_BACK) ||
                        (status == Status.STATUS_MARKED_ROLLBACK)) {
                    return; // it is user's responsibility to rollback the transaction
                    //_transaction.rollback();
                } else {
                    for (int i = 0; i < _txCache.size(); i++) {
                        StateManager sm = (StateManager)_txCache.get(i);
                        sm.flushed();
                    }
                }
                _insideFlush = false;

                // Clear the dirty cache
                _txCache.clear();
            }
        } finally {
            releaseExclusiveLock();
        }
    }

    /**
     * For Transaction to notify PersistenceManager that
     * status is changed
     */
    public synchronized void notifyStatusChange(boolean isActive) {
        _activeTransaction = isActive;
    }

    /**
     * For Transaction to notify PersistenceManager that
     * optimistic flag is changed
     */
    public synchronized void notifyOptimistic(boolean optimistic) {
        this._optimistic = optimistic;
    }

    /**
     * Returns true if associated transaction is optimistic
     */
    public boolean isOptimisticTransaction() {
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug)
            logger.finest("sqlstore.persistencemgr.isoptimistic", new Boolean(_optimistic)); // NOI18N

        return _optimistic;
    }


    /**
     * For Transaction to notify PersistenceManager that
     * nontransactionalRead flag is changed
     */
    public synchronized void notifyNontransactionalRead(boolean nontransactionalRead) {
        this._nontransactionalRead = nontransactionalRead;
    }

    /**
     * Returns true if associated transaction is optimistic
     */
    public boolean isNontransactionalRead() {
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug) {
            logger.finest("sqlstore.persistencemgr.isnontxread",new Boolean(_nontransactionalRead)); // NOI18N
        }

        return _nontransactionalRead;
    }


    /**
     * Returns true if associated transaction is active
     */
    public boolean isActiveTransaction() {
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug)
             logger.finest("sqlstore.persistencemgr.isactivetx",new Boolean(_activeTransaction)); // NOI18N

        return _activeTransaction;
    }

    // Returns current wrapper
    public PersistenceManagerWrapper getCurrentWrapper() {
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug) {
            logger.finest("sqlstore.persistencemgr.getcurrentwrapper",current); // NOI18N
        }

        return current;
    }





    // Remember the current wrapper
    protected void pushCurrentWrapper(PersistenceManagerWrapper pmw) {
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug) {
            Object[] items = new Object[] {current,pmw};
            logger.finest("sqlstore.persistencemgr.pushcurrentwrapper",items); // NOI18N
        }

        current = pmw;
    }

    // Replace current wrapper with the previous
    protected void popCurrentWrapper(PersistenceManagerWrapper prev) {
        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug) {
            Object[] items = new Object[] {current,prev};
            logger.finest("sqlstore.persistencemgr.popcurrentwrapper",items); // NOI18N
        }

        current = prev;
        if (!_isClosed && _jta == null && current == null) {
            this.close();
        }
    }

    /**
     * Assigns reference to javax.transaction.Transaction associated
     * with the current thread in the managed environment
     */
    protected void setJTATransaction(javax.transaction.Transaction t) {
        if (this._jta != null) {
            Object[] items = new Object[] {this._jta, t};
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.setjtatransaction.notnulljta", // NOI18N
                    items));
        }
        this._jta = t;
    }

    /** Add a new created query instance to the queries collection. */
    private void registerQuery(QueryImpl q)
    {
        acquireExclusiveLock();

        try {
            queries.add(q);
        } finally {
            releaseExclusiveLock();
        }
    }

    /**
     * Disconnects all query instances created for this pm and nullifies the
     * collection. This is to allow this pm to be gargabe collected.
     */
    private void disconnectQueries()
    {
        for (Iterator i = queries.iterator(); i.hasNext();)
        {
            QueryImpl q = (QueryImpl)i.next();
            q.clearPersistenceManager();
        }
        queries.clear();
        queries = null;
    }

    /** --------------Private Methods--------------  */

    /**
     * Replace previous value of the SCO field with the newly created
     *
     * @param fieldName the field to notify upon changes
     * @param owner the owner to notify upon changes
     * @param obj new SCO Instance
     */
    private void replaceSCO(String fieldName, Object owner, Object obj) {
        if (owner instanceof PersistenceCapable) {
            acquireShareLock();

            try {
                // Assign this SCO Collection to owner as reference
                PersistenceCapable pc = (PersistenceCapable) owner;
                StateManager sm = pc.jdoGetStateManager();

                if (obj instanceof SCOCollection) {
                    acquireFieldUpdateLock();
                    try {
                        sm.replaceObjectField(fieldName, obj);
                    } finally {
                        releaseFieldUpdateLock();
                    }
                } else {
                    sm.replaceObjectField(fieldName, obj);
                }
            } finally {
                releaseShareLock();
            }
        }
    }

    private Object internalGetObjectId(StateManager sm) {
        Object oid = sm.getObjectId();

        // create a copy
        return internalCloneOid(oid, sm);
    }

    private void internalMakePersistent(PersistenceCapable pc) {
        //
        // We need to lock _fieldUpdateLock here because of
        // the persitence-by-reacheability algorithm that can
        // touch other instances.
        // RESOLVE: We can optimize here to not have to lock
        // _fieldUpdateLock if the instance does not contain any
        // relationship field.
        //
        acquireFieldUpdateLock();
        try {
            synchronized (pc) {
                StateManager sm = null;

                if (pc.jdoIsPersistent()) {
                    sm = pc.jdoGetStateManager();

                    if (this != pc.jdoGetStateManager().getPersistenceManagerInternal()) {
                        throw new JDOUserException(I18NHelper.getMessage(messages,
                                "jdo.persistencemanagerimpl.another_pm"), // NOI18N
                                new Object[]{pc});
                    }
                } else {
                    Class classType = pc.getClass();
                    loadPersistenceConfig(classType);
                    sm = _store.getStateManager(classType);
                }

                sm.makePersistent(this, pc);
            }
        } finally {
            releaseFieldUpdateLock();
        }
    }

    private void internalDeletePersistent(PersistenceCapable pc) {
        if (!(pc.jdoIsPersistent())) {
            throw new JDOException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.internaldeletepersistent.transient"), // NOI18N
                    new Object[]{pc});
        }

        StateManager sm = pc.jdoGetStateManager();
        PersistenceManager pm = (PersistenceManager) sm.getPersistenceManagerInternal();

        if (this != pm) {
            throw new JDOUserException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.another_pm"), // NOI18N
                    new Object[]{pc});
        }

        if (!pc.jdoIsDeleted()) {
            //
            // Synchronization is done in the state manager.
            //
            sm.deletePersistent();
        }
    }

    /**
     * Load metadata for the given OID Object
     * @param oid  the Oid
     * @return classtype for the owning Class
     */
    private Class loadClassForOid(Object oid) {
        Class oidClass = oid.getClass();
        Class classType = _store.getClassByOidClass(oidClass);
        if (classType != null) {
            // Found in the DataStore
            return classType;
        }

        // loadDirectory(oidClass.getName());
        // loadClassByMethod(oid, oidClass);
        loadByName(oidClass.getName(), oidClass.getClassLoader());

        return _store.getClassByOidClass(oidClass);
    }

    /**
     * Load meta data for Object Class from package info
     *
     * @param s     OID class name as String
     * @param classLoader the classLoader of the oid class
     */
    private void loadByName(String s, ClassLoader classLoader) {
        int l = s.length();

        if (l < 4) {
            // Does not fit the pattern
            return;
        }

        String s1 = s.substring(l - 3);

        if (s1.equalsIgnoreCase(oidName_OID) &&
                (s.charAt(l - 4) == '.' || s.charAt(l - 4) == '$')) {
            s = s.substring(0, l - 4);
        } else if (s1.equalsIgnoreCase(oidName_KEY)) {
            s = s.substring(0, l - 3);
        } else {
            return;
        }

        boolean debug = logger.isLoggable(Logger.FINEST);
        if (debug)
            logger.finest("sqlstore.persistencemgr.loadingclass",s); // NOI18N


        Class oidClass = null;

        try {
            // take current class loader if not specified
            if (classLoader == null) {
                classLoader = getClass().getClassLoader();
            }
            oidClass = Class.forName(s, true, classLoader);

        } catch (Exception e) {
            throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.loadclassforoid.wrongoidclass"), e);// NOI18N
        }

        loadPersistenceConfig(oidClass);
    }

    /**
     * assert this PM instance is open
     */
    private void assertIsOpen() {
        if (_isClosed) {
            boolean debug = logger.isLoggable(Logger.FINEST);
            if (debug) {
                logger.finest("sqlstore.persistencemgr.assertisopen",this); // NOI18N
            }
            throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.assertclosed.closed"));// NOI18N
        }
    }

    /**
     * assert that the associated Transaction is active but allows to do commit processing.
     */
    private void assertActiveTransaction(boolean insideQuery) {
        boolean debug = false;

        debug = logger.isLoggable(Logger.FINEST);

        if (debug) {
            logger.finest("sqlstore.persistencemgr.assertactivetx",_transaction); // NOI18N
        }

        if (_insideCommit || (insideQuery && _transaction.getNontransactionalRead()))
            return;

        if (!_activeTransaction) {
            if (debug) {
                logger.finest("sqlstore.persistencemgr.assertactivetx.closed",this); // NOI18N
            }
            throw new JDOException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.assertactivetransaction.error"));// NOI18N
        }
    }

    /**
     * assert Object is PersistenceCapable
     */
    private void assertPersistenceCapable(Object pc) {
        if (!(pc instanceof PersistenceCapable)) {
            throw new JDOException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.assertpersistencecapable.error", // NOI18N
                    pc.getClass().getName()), new Object[]{pc});
        }
    }

    /**
     * Set key field values from Oid into the Object
     *
     * @param sm	StateManager of the Object to set key field values to
     */
    private void setKeyFields(StateManager sm) {
        Object o = sm.getPersistent();
        if (o == null)
            return;

        Object oid = sm.getObjectId();
        try {
            // Set key field vaues and mark them as present
            PersistenceConfig config = sm.getPersistenceConfig();
            Field keyFields[] = config.getKeyFields();
            String keynames[] = config.getKeyFieldNames();
            for (int i = 0; i < keyFields.length; i++) {
                Field keyField = keyFields[i];
                sm.makePresent(keynames[i], keyField.get(oid));
            }

        } catch (Exception e) {
            //e.printStackTrace();
            boolean debug = logger.isLoggable(Logger.FINEST);
            if (debug)
                logger.finest("sqlstore.persistencemgr.setkeyfields",e); // NOI18N
        }
    }

    private PersistenceConfig loadPersistenceConfig(Class classType) {
        return _store.getPersistenceConfig(classType);
    }

    /**
     * Creates local copy of an oid object
     * @param oid 	original object
     * @param sm 	StateManager to be used for the field info.
     * @return 	object 	local copy
     */
    private Object internalCloneOid(Object oid, StateManager sm) {
        if (oid == null)
            return null;

        if (!_requireCopyObjectId) {
            return oid;
        }

        boolean debug = logger.isLoggable(Logger.FINEST);

        Object newoid = null;
        try {
            Class oidClass = oid.getClass();
            newoid = oidClass.newInstance();
            PersistenceConfig config = sm.getPersistenceConfig();
            Field keyFields[] = config.getKeyFields();

            // Copy key field vaues
            for (int i = 0; i < keyFields.length; i++) {
                Field keyField = keyFields[i];
                keyField.set(newoid, keyField.get(oid));
            }

        } catch (Exception e) {
            //e.printStackTrace();
            if (debug)
                logger.finest("sqlstore.persistencemgr.internalcloneoid",e); // NOI18N
            newoid = null;
        }

        if (debug)
            {
            Object[] items = new Object[] {oid , newoid, new Boolean((oid == newoid))};
            logger.finest("sqlstore.persistencemgr.internalcloneoid.old",items); // NOI18N
            }

        return newoid;
    }


    /**
     * Acquires a share lock from the persistence manager. This method will
     * put the calling thread to sleep if another thread is holding the exclusive lock.
     */
    public void acquireShareLock() {
        if ( ! _multithreaded) {
            return;
        }

        boolean debug = logger.isLoggable(Logger.FINEST);

        synchronized (_readWriteLock) {
            //
            // If the current thread is already holding the exclusive lock,
            // we simply grant the share lock without incrementing
            // the counter.
            //
            if ((_readWriteCount < 0) &&
                    (_exclusiveLockHolder == Thread.currentThread())) {
                return;
            }

            //
            // If _readWriteCount is negative, it means a thread is holding the exclusive lock.
            // We simply put this thread to sleep and wait for it to be notified by the
            // thread releasing the exclusive lock.
            //
            while (_readWriteCount < 0) {
                _waiterCount++;

                try {
                    if (debug) {
                        logger.finest("sqlstore.persistencemgr.acquiresharedlock",Thread.currentThread()); // NOI18N
                    }

                    _readWriteLock.wait();
                } catch (InterruptedException e) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "jdo.persistencemanagerimpl.acquiresharelock.interrupted"), e);// NOI18N
                } finally {
                    _waiterCount--;
                }
            }

            try {
                //
                // Make sure no one has closed the pm.
                //
                assertIsOpen();

            } catch (JDOException ex) {
                //
                // If _readWriteCount is 0, it means that no thread is holding a share
                // or exclusive lock. If there is a thread waiting, we wake it up by
                // notifying it.
                //
                if (_readWriteCount == 0 && _waiterCount > 0) {
                    _readWriteLock.notify();
                }
                throw ex;
           }

            _readWriteCount++;
            if (debug) {
              logger.finest("sqlstore.persistencemgr.acquiresharedlock.rdwrcount", // NOI18N
                   Thread.currentThread(),new Long(_readWriteCount));
            }

            if (_readWriteCount <= 0) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "jdo.persistencemanagerimpl.acquiresharelock.failed"));// NOI18N
            }
        }
    }

    /**
     * Releases the share lock and notify any thread waiting to get an exclusive lock.
     * Note that every releaseShareLock() call needs to be preceeded by an acquireShareLock() call.
     */
    public void releaseShareLock() {
        if ( ! _multithreaded) {
            return;
        }

        boolean debug = logger.isLoggable(Logger.FINEST);


        synchronized (_readWriteLock) {
            //
            // If the current thread is already holding the exclusive lock,
            // we simply release the share lock without decrementing
            // the counter.
            //
            if ((_readWriteCount < 0) &&
                    (_exclusiveLockHolder == Thread.currentThread())) {
                return;
            }

            try {
                if (_readWriteCount == 0) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "jdo.persistencemanagerimpl.releasesharelock.failed"));// NOI18N
                }

                _readWriteCount--;
            } finally {
                //
                // If _readWriteCount is 0, it means that no thread is holding a share
                // or exclusive lock. If there is a thread waiting, we wake it up by
                // notifying it.
                //
                if ((_waiterCount > 0) && (_readWriteCount == 0)) {
                    _readWriteLock.notify();
                }

                if (debug) {
                    Object[] items = new Object[] {Thread.currentThread(),new Long(_readWriteCount)};
                    logger.finest("sqlstore.persistencemgr.releasesharedlock",items); // NOI18N
                }
            }
        }
    }

    /**
     * Acquires an exclusive lock from the persistence manager. By acquiring an
     * exclusive lock, a thread is guaranteed to have exclusive right to the persistence
     * runtime meaning no other threads can perform any operation in the sqlstore.
     * NOTE: This implementation does not detect if a thread holding a share lock
     * attempts to acquire an exclusive lock. It is up to the callers to make sure
     * this does not happen.
     */
    public void acquireExclusiveLock() {
        if ( ! _multithreaded) {
            return;
        }

        boolean debug = logger.isLoggable(Logger.FINEST);

        synchronized (_readWriteLock) {
            Thread currentThread = Thread.currentThread();

            //
            // If the current thread already holds the exclusive lock, we simply
            // decrement _readWriteCount to indicate the current level of the exclusive
            // lock.
            //
            if (currentThread == _exclusiveLockHolder) {
                _readWriteCount--;
            } else {
                //
                // If _readWriteCount is not 0, it means that there is either a share lock
                // or an exclusive outstanding. We simply put the current thread to sleep
                // any wait for it to be notified by the thread releasing the lock.
                //
                while (_readWriteCount != 0) {
                    _waiterCount++;

                    try {

                        if (debug) {
                             logger.finest("sqlstore.persistencemgr.acquireexclusivelock",currentThread); // NOI18N
                        }

                        _readWriteLock.wait();
                    } catch (InterruptedException e) {
                        throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                                "jdo.persistencemanagerimpl.acquireexclusivelock.interrupted"), e);// NOI18N
                    } finally {
                        _waiterCount--;
                    }
                }

                try {
                    //
                    // Make sure no one has closed the pm.
                    //
                    assertIsOpen();

                } catch (JDOException ex) {
                    //
                    // If _readWriteCount is 0 and _waiterCount is greater than 0,
                    // we need to notify a thread waiting to acquire a lock.
                    //
                    if (_readWriteCount == 0 && _waiterCount > 0) {
                        _readWriteLock.notify();
                    }
                    throw ex;
               }

                _readWriteCount = -1;
                _exclusiveLockHolder = currentThread;

                if (debug) {
                    Object[] items = new Object[] {currentThread,new Long(_readWriteCount)};
                    logger.fine("sqlstore.persistencemgr.acquireexclusivelock.count",items); // NOI18N
                }

            }
        }
    }

    /**
     * Release the exclusive lock and notify any thread waiting to get an exclusive or
     * share lock. Note that every releaseShareLock() call needs to be preceeded by
     * an acquireExclusiveLock() call.
     */
    public void releaseExclusiveLock() {
        if ( ! _multithreaded) {
            return;
        }

        boolean debug = logger.isLoggable(Logger.FINEST);


        synchronized (_readWriteLock) {
            try {
                if (_readWriteCount >= 0) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "jdo.persistencemanagerimpl.releaseexclusivelock.failed"));// NOI18N
                }

                _readWriteCount++;
            } finally {
                if (debug) {
                    Object[] items = new Object[] {Thread.currentThread(),new Long(_readWriteCount)};
                    logger.finest("sqlstore.persistencemgr.releaseexclusivelock",items); // NOI18N
                }

                //
                // If _readWriteCount is 0 and _waiterCount is greater than 0,
                // we need to notify a thread waiting to acquire a lock.
                //
                if (_readWriteCount == 0) {
                    if (_waiterCount > 0) {
                        _readWriteLock.notify();
                    }

                    _exclusiveLockHolder = null;
                }
            }
        }
    }

    /**
     * Acquire lock for synchronizing field updates.
     */
    public void acquireFieldUpdateLock() {
        _fieldUpdateLock.acquire();
    }

    /**
     * Release lock for synchronizing field updates.
     */
    public void releaseFieldUpdateLock() {
        _fieldUpdateLock.release();
    }

    /**
     * Lock cache for getObjectById and result processing synchronization.
     */
    public void acquireCacheLock() {
        _cacheLock.acquire();
    }

    /** Release cache lock.
     */
    public void releaseCacheLock() {
        _cacheLock.release();
    }

    /** --------------Inner Class--------------  */

    /**
     * Class that implements interface FilenameFilter.
     * Used to filter directory listings in the list method of class File.
     */
    static class ExtensionFilter implements FilenameFilter {
        private String ext;

        public ExtensionFilter(String ext) {
            this.ext = ext;
        }

        /**
         * Tests if a specified file should be included in a file list.
         * @param dir 	the directory in which the file was found
         * @param name	the name of the file
         * @return true if the name should be included in the file list
         */
        public boolean accept(File dir, String name) {
            return name.endsWith(ext);
        }
    }

}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish PersistenceManagerImpl.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.