openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ppod...@apache.org
Subject svn commit: r1240448 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-lib/src/main/java/org/apache/openjpa/lib/util/ openjpa-lib/src/test/java/org/apache/op...
Date Sat, 04 Feb 2012 03:06:46 GMT
Author: ppoddar
Date: Sat Feb  4 03:06:46 2012
New Revision: 1240448

URL: http://svn.apache.org/viewvc?rev=1240448&view=rev
Log:
OPENJPA-2099: Remove hard references from thread local

Added:
    openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/TestFlexibleThreadLocal.java   (with props)
Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
    openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/FlexibleThreadLocal.java

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java?rev=1240448&r1=1240447&r2=1240448&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java Sat Feb  4 03:06:46 2012
@@ -353,7 +353,7 @@ public class JDBCConfigurationImpl
         identifierUtilPlugin.setString(aliases[0]);
         identifierUtilPlugin.setInstantiatingGetter("getIdentifierUtilInstance");
 
-        cacheSelect = new ImmutableBooleanValue("jdbc.CachesSelect", false);
+        cacheSelect = new ImmutableBooleanValue("jdbc.CachesSelect");
         addValue(cacheSelect);
         cacheSelect.setDefault("false");
         

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java?rev=1240448&r1=1240447&r2=1240448&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java Sat Feb  4 03:06:46 2012
@@ -54,9 +54,7 @@ import org.apache.openjpa.jdbc.sql.SQLFa
 import org.apache.openjpa.jdbc.sql.Select;
 import org.apache.openjpa.jdbc.sql.SelectExecutor;
 import org.apache.openjpa.jdbc.sql.Union;
-import org.apache.openjpa.kernel.BrokerImpl;
 import org.apache.openjpa.kernel.FetchConfiguration;
-import org.apache.openjpa.kernel.FinderCache;
 import org.apache.openjpa.kernel.LockManager;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.kernel.PCState;
@@ -87,43 +85,107 @@ import org.apache.openjpa.util.StoreExce
 import org.apache.openjpa.util.UserException;
 
 /**
- * StoreManager plugin that uses JDBC to store persistent data in a
+ * StoreManager plugin that uses JDBC to load and store persistent data in a
  * relational data store.
+ * <br>
+ * This important design construct builds {@link SelectExecutor select} 
+ * structures required to fetch persistent entity from a JDBC database.
+ * The preparation of a select structure requires extensively consulting 
+ * mapping metadata of persistent types. The result of the select execution
+ * as database record is used to populate the persistent attributes. 
+ * <br>
+ * The logic of preparing the select and loading its resultant data are
+ * triggered by this class, but actually carried out by individual field
+ * mapping strategies. This design allows excellent flexibility in terms
+ * of extending behavior by the strategies. 
+ * <br>
+ * This instance is operating under a context i.e. a object management kernel. 
+ * Loading data requires the references to other entities be resolved.
+ * This class delegates reference resolution to this operating context
+ * which may call back to this instance itself to load the reference data.
+ * <br>
+ * This class is aware of transaction and database connection. The database
+ * connections are wrapped with reference counting. Transaction could be
+ * optimistic or pessimistic which broadly translates to connection-less
+ * and connected with respect to database connection. 
+ * <br>
+ * Since version 2.2.0, this critical construct has undergone a major
+ * conceptual change. This construct now is capable of reusing select statements
+ * based on {@link JDBCConfiguration#getSelectCacheEnabled() configuration.
+ * The select instances used by this class are now {@link ClassMapping#getSelect() 
+ * obtained} from the (stateful) mapping metadata instead of a stateless 
+ * {@link SQLFactory factory}.  This allows individual mapping metadata for
+ * a persistent type to maintain a select instance for reuse instead of 
+ * creating yet another cache of selects indexed by their mapping metadata. 
+ * <br>
+ * A reusable select is populated at the first execution and executed subsequently by 
+ * <em>only</em> binding parameters that are specific to a single instance. In concurrent 
+ * execution environment, it is required to ensure that a) the preparation and first 
+ * execution is guarded by synchronized monitor and b) subsequent executions do not 
+ * pay synchronization cost as after first execution a select becomes 
+ * <em>structurally</em> immutable.
+ * <br>
+ * This construct has factored out the methods that executes a select to incorporate
+ * such a threading model. 
+ * <br>
+ * Of course, such structurally immutable select assumes that {@link FetchConfiguration
+ * fetch plan} is invariant as well. However, this construct <em>does not</em> validate 
+ * that assumption at all. As of version 2.2.0, the invariance of fetch plan is <em>not<em>
+ * validated when select cache is activated. 
  *
  * @author Abe White
+ * @author Pinaki Poddar
  * @nojavadoc
  */
 public class JDBCStoreManager implements StoreManager, JDBCStore {
 
-    private static final Localizer _loc = Localizer.forPackage
-        (JDBCStoreManager.class);
+    private static final Localizer _loc = Localizer.forPackage(JDBCStoreManager.class);
 
-    private StoreContext _ctx = null;
-    private JDBCConfiguration _conf = null;
-    private DBDictionary _dict = null;
-    private SQLFactory _sql = null;
-    private JDBCLockManager _lm = null;
-    private DataSource _ds = null;
-    private RefCountConnection _conn = null;
-    private boolean _active = false;
-    private Log _log = null;
+    private StoreContext _ctx;
+    private JDBCConfiguration _conf;
+    private DBDictionary _dict;
+    private JDBCLockManager _lm;
+    private DataSource _ds;
+    private RefCountConnection _conn;
+    private boolean _active;
+    private Log _log;
     
     // track the pending statements so we can cancel them
     private Set<Statement> _stmnts = Collections.synchronizedSet(new HashSet<Statement>());
 
+    /**
+     * Gets the operating context i.e. the object management kernel 
+     * of this store manager.
+     */
     public StoreContext getContext() {
         return _ctx;
     }
 
+    /**
+     * Sets the operating context i.e. the object management kernel 
+     * of this store manager. 
+     * <br>
+     * The context is set before all other operation.
+     */
     public void setContext(StoreContext ctx) {
         setContext(ctx, (JDBCConfiguration) ctx.getConfiguration());
     }
     
+    /**
+     * Sets the operating context i.e. the object management kernel 
+     * of this store manager with the given configuration which may
+     * differ from the configuration of the context. This separation
+     * of configuration allows multiple store manager with different
+     * configuration (e.g. connected to different databases as in Slice)
+     * operating under the same object management kernel and hence
+     * under the same transaction.  
+     * <br>
+     * The context is set before all other operation.
+     */
     public void setContext(StoreContext ctx, JDBCConfiguration conf) {
         _ctx = ctx;
         _conf = conf;
         _dict = _conf.getDBDictionaryInstance();
-        _sql = _conf.getSQLFactoryInstance();
         _log = _conf.getLog(JDBCConfiguration.LOG_DIAG);
 
         LockManager lm = ctx.getLockManager();
@@ -141,15 +203,7 @@ public class JDBCStoreManager implements
     }
         
     private final DataSource getDataSource(StoreContext ctx) {
-        DataSource ds;
-
-        if(useConnectionFactory2(ctx)) { 
-            ds = _conf.getDataSource2(ctx); 
-        }
-        else {
-            ds = _conf.getDataSource(ctx);
-        }
-        return ds; 
+        return (useConnectionFactory2(ctx)) ? _conf.getDataSource2(ctx) : _conf.getDataSource(ctx);
     }
 
     public JDBCConfiguration getConfiguration() {
@@ -161,7 +215,7 @@ public class JDBCStoreManager implements
     }
 
     public SQLFactory getSQLFactory() {
-        return _sql;
+        return _conf.getSQLFactoryInstance();
     }
 
     public JDBCLockManager getLockManager() {
@@ -172,17 +226,36 @@ public class JDBCStoreManager implements
         return (JDBCFetchConfiguration) _ctx.getFetchConfiguration();
     }
 
+    /**
+     * Begins an optimistic transaction. An optimistic transaction does
+     * not retain a connection and hence this method is a no-op.
+     */
     public void beginOptimistic() {
     }
 
+    /**
+     * Rolls back an optimistic transaction. An optimistic transaction does
+     * not retain a connection and hence this method is a no-op.
+     */
     public void rollbackOptimistic() {
     }
 
+    /**
+     * Affirms if the store manager transaction is managed by an external
+     * agency.
+     */
+    public boolean isManaged() {
+    	return _ctx.isManaged() && _conf.isConnectionFactoryModeManaged();
+    }
+    
+    /**
+     * Begins a transaction by setting auto-commit to false, if necessary
+     * in non-managed transaction environment.
+     */
     public void begin() {
         _active = true;
         try {
-            if ((!_ctx.isManaged() || !_conf.isConnectionFactoryModeManaged())
-                && _conn.getAutoCommit())
+            if (!isManaged() && _conn.getAutoCommit())
                 _conn.setAutoCommit(false);
         } catch (SQLException se) {
             _active = false;
@@ -190,9 +263,12 @@ public class JDBCStoreManager implements
         }
     }
 
+    /**
+     * Commits the transaction in non-managed environment.
+     */
     public void commit() {
         try {
-            if (!_ctx.isManaged() || !_conf.isConnectionFactoryModeManaged())
+            if (!isManaged())
                 _conn.commit();
         } catch (SQLException se) {
             try {
@@ -205,15 +281,16 @@ public class JDBCStoreManager implements
         }
     }
 
+    /**
+     * Rolls back the transaction in non-managed environment.
+     */
     public void rollback() {
         // already rolled back ourselves?
         if (!_active)
             return;
 
         try {
-            if (_conn != null
-                && (!_ctx.isManaged() || !_conf
-                    .isConnectionFactoryModeManaged()))
+            if (_conn != null && !isManaged())
                 _conn.rollback();
         } catch (SQLException se) {
             throw SQLExceptions.getStore(se, _dict);
@@ -222,29 +299,54 @@ public class JDBCStoreManager implements
         }
     }
 
+    /**
+     * Retains the connection for later transactions.
+     */
     public void retainConnection() {
         connect(false);
         _conn.setRetain(true);
     }
 
+    /**
+     * Releases the retained connection, if any.
+     */
     public void releaseConnection() {
         if (_conn != null)
             _conn.setRetain(false);
     }
 
+    /**
+     * Gets the client view of the connection as a reference counted 
+     * connection.
+     */
     public Object getClientConnection() {
         return new ClientConnection(getConnection());
     }
 
+    /**
+     * Gets a reference counted connection.
+     */
     public Connection getConnection() {
         connect(true);
         return _conn;
     }
     
+    /**
+     * Gets the data source used by this manager.
+     * @return
+     */
     protected DataSource getDataSource() {
     	return _ds;
     }
 
+    /**
+     * Affirms if the given instance exists in the data store.
+     * Requires to execute a SQL select with primary key identifier
+     * of the given instance. 
+     * 
+     * @param sm the instance whose data store existence is to be determined.
+     * @param context the context in which this query is executed
+     */
     public boolean exists(OpenJPAStateManager sm, Object context) {
         // add where conditions on base class to avoid joins if subclass
         // doesn't use oid as identifier
@@ -252,54 +354,88 @@ public class JDBCStoreManager implements
         return exists(mapping, sm.getObjectId(), context);
     }
 
-    public boolean isCached(List<Object> oids, BitSet edata) {
-        // JDBCStoreManager doesn't store oids in memory.
-        return false;
-    }
-    
+    /**
+     * Executes a SQL select with primary key to ascertain existence
+     * of the given instance.
+     * 
+     * @param mapping the mapping metadata. The where condition is applied
+     * to the least-derived type of this metadata to avoid joins if subclass
+     * does not use the given <tt>oid</tt> as identifer.
+     * @param oid the primary key identifier
+     * @param context the execution context (not used)
+     * @return true if the instance exists in the data store.
+     */
     private boolean exists(ClassMapping mapping, Object oid, Object context) {
         // add where conditions on base class to avoid joins if subclass
         // doesn't use oid as identifier
-        while (mapping.getJoinablePCSuperclassMapping() != null)
-            mapping = mapping.getJoinablePCSuperclassMapping();
+    	mapping = getBaseMapping(mapping);
         Select sel = mapping.getSelect();
-
-        sel.wherePrimaryKey(oid, mapping, this);
-        if (_log.isTraceEnabled()) {
-            _log.trace("exists: oid="+oid+" "+mapping.getDescribedType());
-        }
         try {
-            return sel.getCount(this) != 0;
+        if (requiresLocking(sel)) {
+        	synchronized (sel) {
+        		sel.wherePrimaryKey(oid, mapping, this);
+        		return sel.getCount(this) != 0;
+        	}
+        } else {
+	        sel.wherePrimaryKey(oid, mapping, this);
+	        return sel.getCount(this) != 0;
+        }
         } catch (SQLException se) {
             throw SQLExceptions.getStore(se, _dict);
         }
     }
 
+    /**
+     * Affirms the in-memory version is same as the version of the given instance.
+     */
     public boolean syncVersion(OpenJPAStateManager sm, Object context) {
-        ClassMapping mapping = (ClassMapping) sm.getMetaData();
         try {
-            return mapping.getVersion().checkVersion(sm, this, true);
+            return ((ClassMapping) sm.getMetaData()).getVersion().checkVersion(sm, this, true);
         } catch (SQLException se) {
             throw SQLExceptions.getStore(se, _dict, getReadLockLevel());
         }
     }
 
+    /**
+     * Affirms if this manager has cached the instances given by the
+     * list of identifiers.
+     * <br>
+     * Always returns false as this manager does not have any instance
+     * caching capability. 
+     */
+    public boolean isCached(List<Object> oids, BitSet edata) {
+        // JDBCStoreManager doesn't store oids in memory.
+        return false;
+    }
+    
+    /**
+     * Gets the lock level of the current fetch configuration.
+     * 
+     * @return -1 if no fetch configuration is available.
+     */
     private int getReadLockLevel() {
         JDBCFetchConfiguration fetch = getFetchConfiguration();
-        if (fetch != null) {
-            return fetch.getReadLockLevel();
-        }
-        return -1;
+        return (fetch != null) ? fetch.getReadLockLevel() : -1;
     }
 
+    /**
+     * Compares the two given versions.
+     */
     public int compareVersion(OpenJPAStateManager state, Object v1, Object v2) {
-        ClassMapping mapping = (ClassMapping) state.getMetaData();
-        return mapping.getVersion().compareVersion(v1, v2);
+        return ((ClassMapping) state.getMetaData()).getVersion().compareVersion(v1, v2);
     }
 
-    public boolean initialize(OpenJPAStateManager sm, PCState state,
-        FetchConfiguration fetch, Object context) {
-        ConnectionInfo info = (ConnectionInfo) context;
+    /**
+     * Initializes the persistent state of the given instance to the given state.
+     * 
+     * @param sm the instance to be populated
+     * @param state life cycle state to be set on the given instance 
+     * @param fetch fetch configuration to be used
+     * @param context {@link ConnectionInfo information} about an existing connection.
+     * Could be null if this initialization is non-recursive.
+     */
+    public boolean initialize(OpenJPAStateManager sm, PCState state, FetchConfiguration fetch, Object ctx) {
+        ConnectionInfo info = (ConnectionInfo) ctx;
         try {
             return initializeState(sm, state, (JDBCFetchConfiguration) fetch, info);
         } catch (ClassNotFoundException cnfe) {
@@ -312,9 +448,16 @@ public class JDBCStoreManager implements
 
     /**
      * Initialize a newly-loaded instance.
+     * 
+     * @param sm the instance to be populated
+     * @param state life cycle state to be set on the given instance 
+     * @param fetch fetch configuration to be used
+     * @param info {@link ConnectionInfo information} about an existing connection.
+     * If non-null, then this information carries the database result and exact
+     * metadata of the instance to be loaded.
      */
     protected boolean initializeState(OpenJPAStateManager sm, PCState state,
-        JDBCFetchConfiguration fetch, ConnectionInfo info)
+    	JDBCFetchConfiguration fetch, ConnectionInfo info)
         throws ClassNotFoundException, SQLException {
         Object oid = sm.getObjectId();
         ClassMapping mapping = (ClassMapping) sm.getMetaData();
@@ -378,8 +521,8 @@ public class JDBCStoreManager implements
                 if (mappedByFieldMapping != null && mappedByObject != null)
                     if (mappedByObject instanceof OpenJPAId &&
                         mapping.getExtraFieldDataIndex(mappedByFieldMapping.getIndex()) != -1) {
-                        // The inverse relation can not be set since we are eagerly loading this sm for
-                        // an owner that is still in the process of initializing itself.
+                        // The inverse relation can not be set since we are eagerly loading this instance
+                        // for an owner that is still in the process of initializing itself.
                         // Remember owner oid by setIntermediate().
                         // The inverse relation is set later by setInverseRelation() when the owner is fully
                         // initialized.
@@ -408,8 +551,13 @@ public class JDBCStoreManager implements
         }
     }
 
-    private void setInverseRelation(OpenJPAStateManager owner,
-        ClassMapping mapping, Result res) {
+    /**
+     * Sets inverse relation between eager collection members and the given owner.
+     * @param owner an instance with <em>eager</em> -to-many relation 
+     * @param mapping mapping metadata of the given owner
+     * @param res result carrying the eager results
+     */
+    private void setInverseRelation(OpenJPAStateManager owner, ClassMapping mapping, Result res) {
         FieldMapping[] fms = mapping.getFieldMappings();
 
         // At this point, the owner is fully initialized.
@@ -422,60 +570,62 @@ public class JDBCStoreManager implements
                 Object coll =  owner.fetchObject(fms[i].getIndex());
                 if (coll instanceof Map)
                     coll = ((Map<?,?>)coll).values();
-                if (coll instanceof Collection<?> && 
-                    ((Collection<?>) coll).size() > 0) {
-                    // Found eagerly loaded collection.
-                    // Publisher (1) <==>  (M) Magazine
-                    //    publisher has a EAGER OneToMany relation
-                    //    magazine has a EAGER or LAZY ManyToOne publisher
-                    // For each member (Magazine) in the collection, 
-                    // set its inverse relation (Publisher).
-                    for (Iterator<?> itr = ((Collection<?>) coll).iterator();
-                        itr.hasNext();) {
-                        PersistenceCapable pc = (PersistenceCapable) itr.next();
-                        if (pc == null) {
-                            continue;
-                        }
-                        OpenJPAStateManager sm = (OpenJPAStateManager) pc.pcGetStateManager();
-                        ClassMapping cm =
-                            (ClassMapping) _conf.getMetaDataRepositoryInstance().getCachedMetaData(pc.getClass());
-                        FieldMapping[] fmd = cm.getFieldMappings();
-                        for (int j = 0; j < fmd.length; j++) {
-                            // don't check the oids for basic fields.
-                            if (fmd[j].isTypePC()) {
-                                Object oid = sm.getIntermediate(fmd[j].getIndex());
-                                // if oid was setIntermediate() previously and it is the same as the owner,generate
-                                // then set the inverse relation
-                                if (oid != null && oid.equals(owner.getObjectId())) {
-                                    sm.storeObject(fmd[j].getIndex(), owner.getPersistenceCapable());
-                                    break;
-                                }
-                            }
-                        }
-                    }
+                if (coll instanceof Collection && !((Collection<?>) coll).isEmpty()) {
+                	setInverseRelation(owner, (Collection<?>)coll);
                 }
             }
         }
     }
-
-    protected void setMappedBy(OpenJPAStateManager sm,
-        FieldMapping mappedByFieldMapping, Object mappedByObject) {
-        ClassMapping mapping = (ClassMapping) sm.getMetaData();
-        FieldMapping[] fms = mapping.getFieldMappings();
-        for (int i = 0; i < fms.length; i++) {
-            if (fms[i] == mappedByFieldMapping) {
-                sm.storeObject(fms[i].getIndex(), mappedByObject);
-                return;
+    
+    /**
+     * Sets inverse relation between given owner and given collection members.
+     * <br>
+     * Example: Publisher (1) <---> (M) Magazine <br>
+     *          Publisher has <em>eager</em> OneToMany relation to Magazine<br>
+     *          Magazine has a <em>eager</em> or <em>lazy</em> ManyToOne relation to Publisher<br>
+     *          For each member (Magazine) in the given collection, set the member's inverse
+     *          relation to the Publisher. 
+     */
+    private void setInverseRelation(OpenJPAStateManager owner, Collection<?> coll) {
+        for (Iterator<?> itr = ((Collection<?>) coll).iterator(); itr.hasNext();) {
+        	Object member = itr.next();
+        	if (member instanceof PersistenceCapable) {
+        		PersistenceCapable pc = (PersistenceCapable) member;
+            
+	            OpenJPAStateManager sm = (OpenJPAStateManager) pc.pcGetStateManager();
+	            ClassMapping cm = (ClassMapping)sm.getMetaData();
+	            FieldMapping[] fmd = cm.getFieldMappings();
+	            for (int j = 0; j < fmd.length; j++) {
+	                if (fmd[j].isTypePC()) {
+	                    Object oid = sm.getIntermediate(fmd[j].getIndex());
+	                    if (oid != null && oid.equals(owner.getObjectId())) {
+	                        sm.storeObject(fmd[j].getIndex(), owner.getPersistenceCapable());
+	                        break;
+	                    }
+	                }
+	            }
             }
         }
     }
 
     /**
+     * Sets the given <tt>mappedBy</tt> instance to the given instance to the field that
+     * corresponds to the other end of relation for the given field.
+     * @param sm an instance whose field is to be set
+     * @param mappedByFieldMapping
+     * @param mappedBy
+     */
+    protected void setMappedBy(OpenJPAStateManager sm, FieldMapping mappedByFieldMapping, Object mappedBy) {
+        ClassMapping mapping = (ClassMapping) sm.getMetaData();
+        if (mappedByFieldMapping == mapping.getFieldMapping(mappedByFieldMapping.getIndex()))
+    		sm.storeObject(mappedByFieldMapping.getIndex(), mappedBy);
+    }
+
+    /**
      * This method is to provide override for non-JDBC or JDBC-like 
      * implementation of getting version from the result set.
      */
-    protected void getVersion(ClassMapping mapping, OpenJPAStateManager sm,
-        Result res) throws SQLException {
+    protected void getVersion(ClassMapping mapping, OpenJPAStateManager sm, Result res) throws SQLException {
         mapping.getVersion().afterLoad(sm, this);
     }
     
@@ -484,9 +634,7 @@ public class JDBCStoreManager implements
      * implementation of checking whether the result set is empty or not.
      */
     protected boolean isEmptyResult(Result res) throws SQLException {
-        if (res != null && !res.next())
-            return true;
-        return false;
+        return (res != null && !res.next());
     }
     
     /**
@@ -517,78 +665,159 @@ public class JDBCStoreManager implements
     }
 
     /**
+     * Executes a SQL select statement to obtain the database result for the given instance.
+     * 
+     * @param sm the instance whose database data is to be selected
+     * @param mapping mapping metadata for the given instance
+     * @param fetch the fetch configuration
+     * @param subs subclass joining style indicator. See <tt>Select
      * Select the data for the given instance and return the result. Return
      * null if there is no data in the current fetch groups to select.
      */
-    private Result getInitializeStateResult(OpenJPAStateManager sm,
-        ClassMapping mapping, JDBCFetchConfiguration fetch, int subs)
+    private Result getInitializeStateResult(OpenJPAStateManager sm, ClassMapping mapping, 
+    		JDBCFetchConfiguration fetch, int subs)
         throws SQLException {
-        FinderQueryImpl fq = getFinder(mapping, fetch);
-        if (fq != null)
-            return fq.execute(sm, this, fetch);
         Select sel = mapping.getSelect();
-        if (!select(sel, mapping, subs, sm, null, fetch,
-            JDBCFetchConfiguration.EAGER_JOIN, true, false))
-            return null;
+        if (requiresLocking(sel)) {
+        	synchronized (sel) {
+            	return getInitializeStateResult(sel, sm, mapping, subs, fetch, JDBCFetchConfiguration.EAGER_JOIN);
+        	}
+        } else {
+        	return getInitializeStateResult(sel, sm, mapping, subs, fetch, JDBCFetchConfiguration.EAGER_JOIN);
+        }
+    }
+    
+    /**
+     * Sets the given select with the primary identifier of the given instance and executes 
+     * it to obtain the result used to populate the given instance.
+     * <br>
+     * This method is factored to introduce thread guard for reused selects.
+     * 
+     * @param sel
+     * @param sm
+     * @param mapping
+     * @param subs
+     * @param fetch
+     * @param join
+     * @return
+     * @throws SQLException
+     */
+    private Result getInitializeStateResult(Select sel, OpenJPAStateManager sm, ClassMapping mapping, 
+    		int subs, JDBCFetchConfiguration fetch, int join) throws SQLException {
+        if (!select(sel, mapping, subs, sm, null, fetch, join, true, false))
+	            return null;
         sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
         sel.setExpectedResultCount(1, false);
-        if (_log.isTraceEnabled()) {
-            _log.trace("getInitializeStateResult: oid="+sm.getObjectId()+" "+mapping.getDescribedType());
-        }
-        Result result = sel.execute(this, fetch);
-        cacheFinder(mapping, sel, fetch);
-        return result;
+        return sel.execute(this, fetch);
     }
 
     /**
      * Select a union of the data for the given instance from possible concrete
      * mappings and return the result.
+     * <br>
+     * This method if factored out to ensure that union statement is populated
+     * and executed with synchronization for the first time provided the union
+     * statement is cached and later reused, but subsequent execution of the 
+     * same union statement does not pay any synchronization cost.
      */
     private Result getInitializeStateUnionResult(final OpenJPAStateManager sm,
         ClassMapping mapping, final ClassMapping[] mappings,
         final JDBCFetchConfiguration fetch) throws SQLException {
-        FinderQueryImpl fq = getFinder(mapping, fetch);
-        if (fq != null)
-            return fq.execute(sm, this, fetch);
-        final JDBCStoreManager store = this;
-        final int eager = Math.min(fetch.getEagerFetchMode(),
-            JDBCFetchConfiguration.EAGER_JOIN);
 
         Union union = mapping.getUnion(mappings.length);
+        if (requiresLocking(union)) {
+        	synchronized (union) {
+				return getInitializeStateUnionResult(union, sm, mapping, mappings, fetch);
+			}
+        } else {
+			return getInitializeStateUnionResult(union, sm, mapping, mappings, fetch);
+        }
+    }
+    
+    /**
+     * Executes the given union to obtain the database record for the given instance.
+     * 
+     * @param union an union to be executed to obtain the database record of the given instance.
+     * @param sm the instance for whom a union statement is executed
+     * @param mapping the mapping metadata of the given instance
+     * @param mappings any other independently joinable metadata
+     * @param fetch fetch configuration
+     * @return the selected database result
+     * @throws SQLException when things go wrong
+     */
+    private Result getInitializeStateUnionResult(final Union union, final OpenJPAStateManager sm,
+            ClassMapping mapping, final ClassMapping[] mappings,
+            final JDBCFetchConfiguration fetch) throws SQLException {
+        final JDBCStoreManager store = this;
+        final int eager = Math.min(fetch.getEagerFetchMode(), JDBCFetchConfiguration.EAGER_JOIN);
         union.setExpectedResultCount(1, false);
         if (fetch.getSubclassFetchMode(mapping) != EagerFetchModes.EAGER_JOIN)
             union.abortUnion();
         union.select(new Union.Selector() {
             public void select(Select sel, int i) {
-                sel.select(mappings[i], Select.SUBS_ANY_JOINABLE, store, fetch,
-                    eager);
+                sel.select(mappings[i], Select.SUBS_ANY_JOINABLE, store, fetch, eager);
                 sel.wherePrimaryKey(sm.getObjectId(), mappings[i], store);
             }
         });
-        Result result = union.execute(this, fetch);
-        cacheFinder(mapping, union, fetch);
-        return result;
+        return union.execute(this, fetch);
     }
 
     /**
-     * Select primary key data to make sure the given instance exists, locking
-     * if needed.
+     * Gets the mapping for the least derived type of the given mapping. 
      */
-    private boolean selectPrimaryKey(OpenJPAStateManager sm,
-        ClassMapping mapping, JDBCFetchConfiguration fetch)
-        throws SQLException {
-        // select pks from base class record to ensure it exists and lock
-        // it if needed
+    ClassMapping getBaseMapping(ClassMapping mapping) {
         ClassMapping base = mapping;
-        while (base.getJoinablePCSuperclassMapping() != null)
+        while (base.getJoinablePCSuperclassMapping() != null) {
             base = base.getJoinablePCSuperclassMapping();
+        }
+    	return base;
+    }
 
+    /**
+     * Select primary key data to make sure the given instance exists, locking
+     * if needed.
+     * <br>
+     * Creates or reuses a select. If selects are cached, then ensures that 
+     * first preparation and execution is synchronized, but the subsequent
+     * executions are unsynchronized.
+     */
+    private boolean selectPrimaryKey(OpenJPAStateManager sm, ClassMapping mapping, JDBCFetchConfiguration fetch)
+        throws SQLException {
         Select sel = mapping.getSelect();
+        if (requiresLocking(sel)) {
+        	synchronized (sel) {
+        		return selectPrimaryKey(sel, sm, mapping, fetch);
+        	} 
+        } else {
+    		return selectPrimaryKey(sel, sm, mapping, fetch);
+        }
+    }
+    
+    /**
+     * Affirms if the given select needs to be populated and executed with
+     * thread synchronization guard.
+     */
+    private boolean requiresLocking(SelectExecutor sel) {
+    	return !sel.isReadOnly() && _conf.getSelectCacheEnabled();
+    }
+    
+    /**
+     * Executes the given Select to find whether the given object exists. 
+     * This method is factored out to be executed with synchronization
+     * at first execution when select caching is turned on by configuration. 
+     * @param sel a select to execute to find existence of the given oject
+     * @param sm the given object
+     * @param mapping the mapping for the given object
+     * @param fetch fetch configuration determines if locking is required
+     * @return true if the object exists
+     * @throws SQLException when things go wrong
+     * @see #selectPrimaryKey(OpenJPAStateManager, ClassMapping, JDBCFetchConfiguration)
+     */
+    private boolean selectPrimaryKey(Select sel, OpenJPAStateManager sm, ClassMapping mapping, 
+    		JDBCFetchConfiguration fetch) throws SQLException {
+    	ClassMapping base = getBaseMapping(mapping);
         sel.select(base.getPrimaryKeyColumns());
         sel.wherePrimaryKey(sm.getObjectId(), base, this);
-        if (_log.isTraceEnabled()) {
-            _log.trace("selectPrimaryKey: oid="+sm.getObjectId()+" "+mapping.getDescribedType());
-        }
         Result exists = sel.execute(this, fetch);
         try {
             if (isEmptyResult(exists))
@@ -628,48 +857,69 @@ public class JDBCStoreManager implements
 
             // if the instance is hollow and there's a customized
             // get by id method, use it
-            if (sm.getLoaded().length() == 0 
-                && mapping.customLoad(sm, this, null, jfetch))
+            if (sm.getLoaded().length() == 0 && mapping.customLoad(sm, this, null, jfetch)) {
                 removeLoadedFields(sm, fields);
-
-            //### select is kind of a big object, and in some cases we don't
-            //### use it... would it be worth it to have a small shell select
-            //### object that only creates a real select when actually used?
-
+            }
             Select sel = mapping.getSelect();
-            if (select(sel, mapping, Select.SUBS_EXACT, sm, fields, jfetch,
+            
+            if (requiresLocking(sel)) {
+            	synchronized (sel) {
+                	if (selectAndLoad(sel, mapping, sm, fields, jfetch, lockLevel) == Boolean.FALSE)
+                		return false;
+				}
+            } else {
+            	if (selectAndLoad(sel, mapping, sm, fields, jfetch, lockLevel) == Boolean.FALSE)
+            		return false;
+            }
+            
+            // now allow the fields to load themselves individually too
+            FieldMapping[] fms = mapping.getFieldMappings();
+            for (int i = 0; i < fms.length; i++) {
+                if (fields.get(i) && !sm.getLoaded().get(i)) {
+                    fms[i].load(sm, this, jfetch.traverseJDBC(fms[i]));
+                }
+            }
+            mapping.getVersion().afterLoad(sm, this);
+            return true;
+        } catch (ClassNotFoundException cnfe) {
+            throw new StoreException(cnfe);
+        } catch (SQLException se) {
+            throw SQLExceptions.getStore(se, _dict, lockLevel);
+        }
+    }
+    
+    /**
+     * Populates the given select, executes it and loads the resultant data into the given instance. 
+     * @param sel
+     * @param mapping
+     * @param sm
+     * @param fields
+     * @param jfetch
+     * @param lockLevel
+     * @return false if the instance does not exist anymore. true if it were loaded.
+     * null if select is not required
+     * @throws SQLException
+     */
+    private Boolean selectAndLoad(Select sel, ClassMapping mapping, OpenJPAStateManager sm, BitSet fields, 
+    		JDBCFetchConfiguration jfetch, int lockLevel) throws SQLException {
+        if (select(sel, mapping, Select.SUBS_EXACT, sm, fields, jfetch,
                 EagerFetchModes.EAGER_JOIN, true, false)) {
                 sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
                 if (_log.isTraceEnabled()) {
                     _log.trace("load: "+mapping.getDescribedType()+" oid: "+sm.getObjectId()); 
                 }
-                res = sel.execute(this, jfetch, lockLevel);
+                Result res = sel.execute(this, jfetch, lockLevel);
                 try {
                  	if (isEmptyResult(res))
                         return false;
                     load(mapping, sm, jfetch, res);
+                    return true;
                 } finally {
                     res.close();
                 }
             }
+        return null;
 
-            // now allow the fields to load themselves individually too
-            FieldMapping[] fms = mapping.getFieldMappings();
-            for (int i = 0; i < fms.length; i++)
-                if (fields.get(i) && !sm.getLoaded().get(i)) {
-                    if (_log.isTraceEnabled()) {
-                        _log.trace("load field: '"+ fms[i].getName() + "' for oid="+sm.getObjectId()
-                            +" "+mapping.getDescribedType());
-                    }
-                    fms[i].load(sm, this, jfetch.traverseJDBC(fms[i]));
-                }
-            mapping.getVersion().afterLoad(sm, this);
-            return true;
-        } catch (ClassNotFoundException cnfe) {
-            throw new StoreException(cnfe);
-        } catch (SQLException se) {
-            throw SQLExceptions.getStore(se, _dict, lockLevel);
-        }
     }
 
     /**
@@ -681,26 +931,20 @@ public class JDBCStoreManager implements
                 fields.clear(i);
     }
 
-    public Collection loadAll(Collection sms, PCState state, int load,
+    public Collection<Object> loadAll(Collection<OpenJPAStateManager> sms, PCState state, int load,
         FetchConfiguration fetch, Object context) {
         return ImplHelper.loadAll(sms, this, state, load, fetch, context);
     }
 
-    public void beforeStateChange(OpenJPAStateManager sm, PCState fromState,
-        PCState toState) {
+    public void beforeStateChange(OpenJPAStateManager sm, PCState fromState, PCState toState) {
     }
 
-    public Collection flush(Collection sms) {
+    public Collection<Exception> flush(Collection<OpenJPAStateManager> sms) {
         try {
             if (_conn != null && _conn.getInnermostDelegate().isReadOnly())
                 _conn.setReadOnly(false);
         } catch (SQLException e) {
         }
-        if (_log.isTraceEnabled()) {
-            for (OpenJPAStateManager sm: (Collection<OpenJPAStateManager>)sms) {
-                _log.trace("flush: "+sm.getPCState().getClass().getName() + " for oid="+sm.getObjectId());
-            }
-        }
         return _conf.getUpdateManagerInstance().flush(sms, this);
     }
 
@@ -717,8 +961,8 @@ public class JDBCStoreManager implements
         }
 
         try {
-            for (Iterator<Statement> itr = stmnts.iterator(); itr.hasNext();)
-                ((Statement) itr.next()).cancel();
+            for (Statement stmnt : stmnts)
+                stmnt.cancel();
             return true;
         } catch (SQLException se) {
             throw SQLExceptions.getStore(se, _dict);
@@ -731,8 +975,7 @@ public class JDBCStoreManager implements
             return ApplicationIds.assign(sm, this, preFlush);
 
         // datastore identity
-        Object val = ImplHelper.generateIdentityValue(_ctx, meta,
-            JavaTypes.LONG);
+        Object val = ImplHelper.generateIdentityValue(_ctx, meta, JavaTypes.LONG);
         if (val == null && meta.getIdentityStrategy() != ValueStrategies.NATIVE)
             return false;
         if (val == null)
@@ -752,9 +995,7 @@ public class JDBCStoreManager implements
     }
 
     public Class<?> getManagedType(Object oid) {
-        if (oid instanceof Id)
-            return ((Id) oid).getType();
-        return null;
+        return (oid instanceof Id) ? ((Id) oid).getType() : null;
     }
 
     public Class<?> getDataStoreIdType(ClassMetaData meta) {
@@ -815,18 +1056,11 @@ public class JDBCStoreManager implements
                         _log.trace("executeExtent: "+mappings[i].getDescribedType());
                         sel.logEagerRelations();
                     }
-                    BitSet paged = selectExtent(sel, mappings[i], jfetch,
-                        subclasses);
-                    if (paged == null)
-                        rops[i] = new InstanceResultObjectProvider(sel,
-                            mappings[i], this, jfetch);
-                    else
-                        rops[i] = new PagingResultObjectProvider(sel,
-                            mappings[i], this, jfetch, paged, Long.MAX_VALUE);
+                    BitSet paged = selectExtent(sel, mappings[i], jfetch, subclasses);
+                    rops[i] = (paged == null) ? new InstanceResultObjectProvider(sel, mappings[i], this, jfetch)
+                            : new PagingResultObjectProvider(sel, mappings[i], this, jfetch, paged, Long.MAX_VALUE);
                 }
-                if (rops.length == 1)
-                    return rops[0];
-                return new MergedResultObjectProvider(rops);
+                return (rops.length == 1) ? rops[0] : new MergedResultObjectProvider(rops);
             }
 
             // perform a union on all independent classes
@@ -845,8 +1079,7 @@ public class JDBCStoreManager implements
                     return new PagingResultObjectProvider(union, mappings,
                         JDBCStoreManager.this, jfetch, paged, Long.MAX_VALUE);
             }
-            return new InstanceResultObjectProvider(union, mappings[0], this,
-                jfetch);
+            return new InstanceResultObjectProvider(union, mappings[0], this, jfetch);
         } catch (SQLException se) {
             throw SQLExceptions.getStore(se, _dict);
         }
@@ -859,15 +1092,12 @@ public class JDBCStoreManager implements
         JDBCFetchConfiguration fetch, boolean subclasses) {
         int subs = (subclasses) ? Select.SUBS_JOINABLE : Select.SUBS_NONE;
         // decide between paging and standard iteration
-        BitSet paged = PagingResultObjectProvider.getPagedFields(sel, mapping,
-            this, fetch, JDBCFetchConfiguration.EAGER_PARALLEL,
-            Long.MAX_VALUE);
+        BitSet paged = PagingResultObjectProvider.getPagedFields(sel, mapping, this, fetch, 
+        		JDBCFetchConfiguration.EAGER_PARALLEL, Long.MAX_VALUE);
         if (paged == null)
-            sel.selectIdentifier(mapping, subs, this, fetch,
-                JDBCFetchConfiguration.EAGER_PARALLEL);
+            sel.selectIdentifier(mapping, subs, this, fetch, JDBCFetchConfiguration.EAGER_PARALLEL);
         else
-            sel.selectIdentifier(mapping, subs, this, fetch,
-                JDBCFetchConfiguration.EAGER_JOIN);
+            sel.selectIdentifier(mapping, subs, this, fetch, JDBCFetchConfiguration.EAGER_JOIN);
         return paged;
     }
 
@@ -875,14 +1105,13 @@ public class JDBCStoreManager implements
         ExpressionParser ep = QueryLanguages.parserForLanguage(language);
         if (ep != null) { 
             return new JDBCStoreQuery(this, ep);
-        }
-        if (QueryLanguages.LANG_SQL.equals(language)) {
+        } else if (QueryLanguages.LANG_SQL.equals(language)) {
             return new SQLStoreQuery(this);
-        }
-        if (QueryLanguages.LANG_PREPARED_SQL.equals(language)) {
+        } else if (QueryLanguages.LANG_PREPARED_SQL.equals(language)) {
             return new PreparedSQLStoreQuery(this);
+        } else {
+        	return null;
         }
-        return null;
     }
     
     public StoreQuery newQuery(String language) {
@@ -904,10 +1133,9 @@ public class JDBCStoreManager implements
     }
 
     public Seq getDataStoreIdSequence(ClassMetaData meta) {
-        if (meta.getIdentityStrategy() == ValueStrategies.NATIVE
-            || meta.getIdentityStrategy() == ValueStrategies.NONE)
-            return _conf.getSequenceInstance();
-        return null;
+        return (meta.getIdentityStrategy() == ValueStrategies.NATIVE
+            || meta.getIdentityStrategy() == ValueStrategies.NONE) 
+            ? _conf.getSequenceInstance() : null;
     }
 
     public Seq getValueSequence(FieldMetaData fmd) {
@@ -961,13 +1189,9 @@ public class JDBCStoreManager implements
     /**
      * Find the object with the given oid.
      */
-    public Object find(Object oid, ValueMapping vm, 
-        JDBCFetchConfiguration fetch) {
+    public Object find(Object oid, ValueMapping vm, JDBCFetchConfiguration fetch) {
         if (oid == null)
             return null;
-        if (_log.isTraceEnabled()) {
-            _log.trace("find: oid="+oid+" "+vm.getDeclaredTypeMapping().getDescribedType());
-        }
         Object pc = _ctx.find(oid, fetch, null, null, 0);
         if (pc == null && vm != null) {
             OrphanedKeyAction action = _conf.getOrphanedKeyActionInstance();
@@ -979,16 +1203,13 @@ public class JDBCStoreManager implements
     /**
      * Load the object in the current row of the given result.
      */
-    public Object load(ClassMapping mapping, JDBCFetchConfiguration fetch,
-        BitSet exclude, Result result) throws SQLException {
+    public Object load(ClassMapping mapping, JDBCFetchConfiguration fetch, BitSet exclude, Result result) 
+        throws SQLException {
         if (!mapping.isMapped())
-            throw new InvalidStateException(_loc.get("virtual-mapping", 
-                mapping));
+            throw new InvalidStateException(_loc.get("virtual-mapping", mapping));
 
         // get the object id for the row; base class selects pk columns
-        ClassMapping base = mapping;
-        while (base.getJoinablePCSuperclassMapping() != null)
-            base = base.getJoinablePCSuperclassMapping();
+        ClassMapping base = getBaseMapping(mapping);
         Object oid = base.getObjectId(this, result, null, true, null);
         if (oid == null)
             return null;
@@ -1023,15 +1244,11 @@ public class JDBCStoreManager implements
      * Load the given state manager with data from the result set. Only
      * mappings originally selected will be loaded.
      */
-    private void load(ClassMapping mapping, OpenJPAStateManager sm,
-        JDBCFetchConfiguration fetch, Result res) throws SQLException {
+    private void load(ClassMapping mapping, OpenJPAStateManager sm, JDBCFetchConfiguration fetch, Result res) 
+        throws SQLException {
         FieldMapping eagerToMany = load(mapping, sm, fetch, res, null);
         if (eagerToMany != null) {
-            if (_log.isTraceEnabled()) {
-                _log.trace("Loading eager toMany: "+eagerToMany.getName()+" for "+mapping);
-            }
-            eagerToMany.loadEagerJoin(sm, this, fetch.traverseJDBC(eagerToMany),
-                res);
+            eagerToMany.loadEagerJoin(sm, this, fetch.traverseJDBC(eagerToMany), res);
         }
         if (_active && _lm != null && res.isLocking())
             _lm.loadedForUpdate(sm);
@@ -1049,11 +1266,11 @@ public class JDBCStoreManager implements
 
         // load superclass data; base class loads version
         ClassMapping parent = mapping.getJoinablePCSuperclassMapping();
-        if (parent != null)
+        if (parent != null) {
             eagerToMany = load(parent, sm, fetch, res, eagerToMany);
-        else if (sm.getVersion() == null)
+        } else if (sm.getVersion() == null) {
             mapping.getVersion().load(sm, this, res);
-
+        }
         // load unloaded fields
         FieldMapping[] fms = mapping.getDefinedFieldMappings();
         Object eres, processed;
@@ -1069,11 +1286,9 @@ public class JDBCStoreManager implements
                     if (eagerToMany == null && fms[i].isEagerSelectToMany())
                         eagerToMany = fms[i];
                     else
-                        fms[i].loadEagerJoin(sm, this, 
-                        	fetch.traverseJDBC(fms[i]), res);
+                        fms[i].loadEagerJoin(sm, this, fetch.traverseJDBC(fms[i]), res);
                 } else if (eres != null) {
-                    processed = fms[i].loadEagerParallel(sm, this, 
-                    	fetch.traverseJDBC(fms[i]), eres);
+                    processed = fms[i].loadEagerParallel(sm, this, fetch.traverseJDBC(fms[i]), eres);
                     if (processed != eres)
                         res.putEager(fms[i], processed);
                 } else {
@@ -1118,7 +1333,7 @@ public class JDBCStoreManager implements
     		return true;
         // add class conditions so that they're cloned for any batched selects
         boolean joinedSupers = false;    
-        if(needClassCondition(mapping, subs, sm)) {
+        if (needClassCondition(mapping, subs, sm)) {
             joinedSupers = getJoinedSupers(sel, mapping, subs, outer);
         }
         
@@ -1132,7 +1347,7 @@ public class JDBCStoreManager implements
         // the joins needed by these selects don't get in the WHERE clause
         // of the batched selects
         int seld = selectBaseMappings(sel, mapping, mapping, sm, fields,
-            fetch, eager, eagerToMany, ident, joinedSupers);
+        		fetch, eager, eagerToMany, ident, joinedSupers);
 
         // select eager to-many relations last because during load they
         // advance the result set and could exhaust it, so no other mappings
@@ -1155,35 +1370,29 @@ public class JDBCStoreManager implements
     }
     
     private boolean needClassCondition(ClassMapping mapping, int subs, OpenJPAStateManager sm) {
-        boolean retVal = false;
-        if(sm == null || sm.getPCState() == PCState.TRANSIENT) {
-            if(subs == Select.SUBS_JOINABLE || subs == Select.SUBS_NONE) {
-                retVal = true;
-            }
-            else {
-                if (mapping.getDiscriminator() != null
-                    && SuperclassDiscriminatorStrategy.class.isInstance(mapping.getDiscriminator().getStrategy())
-                    && mapping.getMappingRepository().getConfiguration().getCompatibilityInstance()
-                        .getSuperclassDiscriminatorStrategyByDefault()) {
-                    retVal = true;
-                }
+        if (sm == null || sm.getPCState() == PCState.TRANSIENT) {
+            if (subs == Select.SUBS_JOINABLE || subs == Select.SUBS_NONE) {
+                return true;
+            } else {
+                return (mapping.getDiscriminator() != null
+                     && SuperclassDiscriminatorStrategy.class.isInstance(mapping.getDiscriminator().getStrategy())
+                     && _conf.getCompatibilityInstance().getSuperclassDiscriminatorStrategyByDefault());
             }
         }
-        return retVal;
+        return false;
     }
     
     /**
      * Mark the fields of this mapping as reserved so that eager fetches can't
      * get into infinite recursive situations.
      */
-    private FieldMapping createEagerSelects(Select sel, ClassMapping mapping,
-        OpenJPAStateManager sm, BitSet fields, JDBCFetchConfiguration fetch,
-        int eager) {
+    private FieldMapping createEagerSelects(Select sel, ClassMapping mapping, OpenJPAStateManager sm, 
+        BitSet fields, JDBCFetchConfiguration fetch, int eager) {
         if (mapping == null || eager == JDBCFetchConfiguration.EAGER_NONE)
             return null;
 
         FieldMapping eagerToMany = createEagerSelects(sel, 
-            mapping.getJoinablePCSuperclassMapping(), sm, fields, fetch, eager);
+        		mapping.getJoinablePCSuperclassMapping(), sm, fields, fetch, eager);
 
         FieldMapping[] fms = mapping.getDefinedFieldMappings();
         boolean inEagerJoin = sel.hasEagerJoin(false);
@@ -1229,10 +1438,8 @@ public class JDBCStoreManager implements
 
             // finally, try parallel
             if (eager == EagerFetchModes.EAGER_PARALLEL
-                && (sels = fms[i].supportsSelect(sel, Select.EAGER_PARALLEL, sm,
-                this, fetch)) != 0)
-                sel.eagerClone(fms[i], Select.EAGER_PARALLEL, 
-                    fms[i].isEagerSelectToMany(), sels);
+            && (sels = fms[i].supportsSelect(sel, Select.EAGER_PARALLEL, sm, this, fetch)) != 0)
+                sel.eagerClone(fms[i], Select.EAGER_PARALLEL, fms[i].isEagerSelectToMany(), sels);
         }
         return eagerToMany;
     }
@@ -1244,8 +1451,7 @@ public class JDBCStoreManager implements
         OpenJPAStateManager sm, BitSet fields, JDBCFetchConfiguration fetch) {
         if (fields != null)
             return fields.get(fm.getIndex());
-        if (sm != null && sm.getPCState() != PCState.TRANSIENT
-            && sm.getLoaded().get(fm.getIndex()))
+        if (sm != null && sm.getPCState() != PCState.TRANSIENT && sm.getLoaded().get(fm.getIndex()))
             return false;
         return fetch.requiresFetch(fm) == FetchConfiguration.FETCH_LOAD;
     }
@@ -1265,14 +1471,12 @@ public class JDBCStoreManager implements
      * @return &gt; 0 if the select is required, 0 if data was
      * selected but is not required, and &lt; 0 if nothing was selected
      */
-    private int selectBaseMappings(Select sel, ClassMapping mapping,
-        ClassMapping orig, OpenJPAStateManager sm, BitSet fields,
-        JDBCFetchConfiguration fetch, int eager, FieldMapping eagerToMany,
+    private int selectBaseMappings(Select sel, ClassMapping mapping, ClassMapping orig, OpenJPAStateManager sm, 
+        BitSet fields, JDBCFetchConfiguration fetch, int eager, FieldMapping eagerToMany, 
         boolean ident, boolean joined) {
         ClassMapping parent = mapping.getJoinablePCSuperclassMapping();
         if (parent == null && !mapping.isMapped())
-            throw new InvalidStateException(_loc.get("virtual-mapping", mapping.
-                getDescribedType()));
+            throw new InvalidStateException(_loc.get("virtual-mapping", mapping.getDescribedType()));
 
         int seld = -1;
         int pseld = -1;
@@ -1296,23 +1500,18 @@ public class JDBCStoreManager implements
                 seld = 1;
 
             // if no instance or no version, select version
-            if ((sm == null || sm.getVersion() == null)
-                && mapping.getVersion().select(sel, orig))
+            if ((sm == null || sm.getVersion() == null) && mapping.getVersion().select(sel, orig))
                 seld = 1;
-        } else {
-            // recurse on parent
-            pseld = selectBaseMappings(sel, parent, orig, sm, fields,
-                fetch, eager, eagerToMany, ident, joined);
+        } else { // recurse on parent
+            pseld = selectBaseMappings(sel, parent, orig, sm, fields, fetch, eager, eagerToMany, ident, joined);
         }
 
-        // select the mappings in the given fields set, or based on fetch
-        // configuration if no fields given
+        // select the mappings in the given fields set, or based on fetch configuration if no fields given
         FieldMapping[] fms = mapping.getDefinedFieldMappings();
         SelectExecutor esel;
         int fseld;
         for (int i = 0; i < fms.length; i++) {
-            // skip eager to-many select; we do that separately in calling
-            // method
+            // skip eager to-many select; we do that separately in calling method
             if (fms[i] == eagerToMany)
                 continue;
 
@@ -1320,31 +1519,24 @@ public class JDBCStoreManager implements
             esel = sel.getEager(fms[i]);
             if (esel != null) {
                 if (esel == sel)
-                    fms[i].selectEagerJoin(sel, sm, this, 
-                    	fetch.traverseJDBC(fms[i]), eager);
+                    fms[i].selectEagerJoin(sel, sm, this, fetch.traverseJDBC(fms[i]), eager);
                 else
-                    fms[i].selectEagerParallel(esel, sm, this, 
-                    	fetch.traverseJDBC(fms[i]), eager);
+                    fms[i].selectEagerParallel(esel, sm, this, fetch.traverseJDBC(fms[i]), eager);
                 seld = Math.max(0, seld);
             } else if (requiresSelect(fms[i], sm, fields, fetch)) {
-                fseld = fms[i].select(sel, sm, this, 
-                	fetch.traverseJDBC(fms[i]), eager);
+                fseld = fms[i].select(sel, sm, this, fetch.traverseJDBC(fms[i]), eager);
                 seld = Math.max(fseld, seld);
             } else if (optSelect(fms[i], sel, sm, fetch)) {
-                fseld = fms[i].select(sel, sm, this, 
-                	fetch.traverseJDBC(fms[i]), EagerFetchModes.EAGER_NONE);
+                fseld = fms[i].select(sel, sm, this, fetch.traverseJDBC(fms[i]), EagerFetchModes.EAGER_NONE);
 
-                // don't upgrade seld to > 0 based on these fields, since
-                // they're not in the calculated field set
+                // don't upgrade seld to > 0 based on these fields, since they're not in the calculated field set
                 if (fseld >= 0 && seld < 0)
                     seld = 0;
             }
         }
 
-        // in certain circumstances force join to superclass table to avoid
-        // SQL generation error.
-        if ( eagerToMany != null && pseld < 0 && !joined
-                && parent != null ) {
+        // in certain circumstances force join to superclass table to avoid SQL generation error.
+        if (eagerToMany != null && pseld < 0 && !joined && parent != null) {
             FieldMapping[] pfms = parent.getDefinedFieldMappings();
             for (int i = 0; i < pfms.length; i++) {
                 if (pfms[i] == eagerToMany ) {
@@ -1354,8 +1546,7 @@ public class JDBCStoreManager implements
             }
         }
         
-        // join to parent table if the parent / any ancestors have selected
-        // anything
+        // join to parent table if the parent / any ancestors have selected anything
         if (!joined && pseld >= 0 && parent.getTable() != mapping.getTable())
             sel.where(mapping.joinSuperclass(sel.newJoins(), false));
 
@@ -1369,9 +1560,8 @@ public class JDBCStoreManager implements
      * optimization.
      */
     private boolean optSelect(FieldMapping fm, Select sel, OpenJPAStateManager sm, JDBCFetchConfiguration fetch) {
-        boolean dfg =
-            fetch.getIgnoreDfgForFkSelect() || 
-                !fm.isInDefaultFetchGroup() && !fm.isDefaultFetchGroupExplicit();
+        boolean dfg = fetch.getIgnoreDfgForFkSelect() || 
+                    !fm.isInDefaultFetchGroup() && !fm.isDefaultFetchGroupExplicit();
 
         return dfg && (sm == null || sm.getPCState() == PCState.TRANSIENT || !sm.getLoaded().get(fm.getIndex()))
             && fm.supportsSelect(sel, Select.TYPE_TWO_PART, sm, this, fetch) > 0;
@@ -1386,8 +1576,9 @@ public class JDBCStoreManager implements
      * @param sm the instance being selected for, or null if none
      * @param fetch the fetch configuration
      */
-    private void selectSubclassMappings(Select sel, ClassMapping mapping,
-        OpenJPAStateManager sm, JDBCFetchConfiguration fetch) {
+    private void selectSubclassMappings(Select sel, ClassMapping mapping, 
+    		OpenJPAStateManager sm, JDBCFetchConfiguration fetch) {
+        
         loadSubclasses(mapping);
         ClassMapping[] subMappings = mapping.getJoinablePCSubclassMappings();
         if (subMappings.length == 0)
@@ -1403,10 +1594,9 @@ public class JDBCStoreManager implements
         FieldMapping[] fms;
         boolean joined;
         boolean canJoin = _dict.joinSyntax != JoinSyntaxes.SYNTAX_TRADITIONAL
-            && fetch.getSubclassFetchMode(mapping) != fetch.EAGER_NONE;
+            && fetch.getSubclassFetchMode(mapping) != JDBCFetchConfiguration.EAGER_NONE;
         for (int i = 0; i < subMappings.length; i++) {
-            if (!subMappings[i].supportsEagerSelect(sel, sm, this, mapping,
-                fetch))
+            if (!subMappings[i].supportsEagerSelect(sel, sm, this, mapping, fetch))
                 continue;
 
             // initialize so that if we can't join, we pretend we already have
@@ -1417,8 +1607,7 @@ public class JDBCStoreManager implements
             	if (fetch.requiresFetch(fms[j]) != FetchConfiguration.FETCH_LOAD
                     && ((!fms[j].isInDefaultFetchGroup() 
                     && fms[j].isDefaultFetchGroupExplicit())
-                    || fms[j].supportsSelect(sel, Select.TYPE_TWO_PART, sm, this, 
-                    fetch) <= 0)) 
+                    || fms[j].supportsSelect(sel, Select.TYPE_TWO_PART, sm, this, fetch) <= 0)) 
             		continue;
 
                 // if we can join to the subclass, do so; much better chance
@@ -1441,10 +1630,8 @@ public class JDBCStoreManager implements
      * Helper method to join from class to its subclass. Recursive to allow
      * for multiple hops, starting from the base class.
      */
-    private static Joins joinSubclass(Select sel, ClassMapping base,
-        ClassMapping sub, Joins joins) {
-        if (sub == base || sub.getTable() == base.getTable()
-            || sel.isSelected(sub.getTable()))
+    private static Joins joinSubclass(Select sel, ClassMapping base, ClassMapping sub, Joins joins) {
+        if (sub == base || sub.getTable() == base.getTable() || sel.isSelected(sub.getTable()))
             return null;
 
         // recurse first so we go least->most derived
@@ -1465,8 +1652,7 @@ public class JDBCStoreManager implements
             return;
 
         // if the subclass list is set, no need to load subs
-        if (mapping.getRepository().getPersistentTypeNames(false,
-            _ctx.getClassLoader()) != null) {
+        if (mapping.getRepository().getPersistentTypeNames(false, _ctx.getClassLoader()) != null) {
             dsc.setSubclassesLoaded(true);
             return;
         }
@@ -1494,22 +1680,6 @@ public class JDBCStoreManager implements
         _stmnts.remove(stmnt);
     }
     
-    FinderQueryImpl getFinder(ClassMapping mapping, FetchConfiguration fetch) {
-        FinderCache cache = getFinderCache();
-        return cache == null 
-             ? null : (FinderQueryImpl)cache.get(mapping, fetch);
-    }
-    
-    boolean cacheFinder(ClassMapping mapping, SelectExecutor select, 
-        FetchConfiguration fetch) {
-        FinderCache cache = getFinderCache();
-        return cache != null && cache.cache(mapping, select, fetch) != null;
-    }
-    
-    FinderCache getFinderCache() {
-        return (((BrokerImpl)getContext()).getCacheFinderQuery())
-             ? getConfiguration().getFinderCacheInstance() : null;
-    }
 
     /**
      * Connection returned to client code. Makes sure its wrapped connection ref count is decremented on finalize.
@@ -1595,27 +1765,24 @@ public class JDBCStoreManager implements
         }
 
         protected Statement createStatement(boolean wrap) throws SQLException {
-            return new CancelStatement(super.createStatement(false),
-                RefCountConnection.this);
+            return new CancelStatement(super.createStatement(false), RefCountConnection.this);
         }
 
         protected Statement createStatement(int rsType, int rsConcur,
             boolean wrap) throws SQLException {
-            return new CancelStatement(super.createStatement(rsType, rsConcur,
-                false), RefCountConnection.this);
+            return new CancelStatement(super.createStatement(rsType, rsConcur, false), RefCountConnection.this);
 
         }
 
         protected PreparedStatement prepareStatement(String sql, boolean wrap)
             throws SQLException {
-            return new CancelPreparedStatement(super.prepareStatement(sql,
-                false), RefCountConnection.this);
+            return new CancelPreparedStatement(super.prepareStatement(sql, false), RefCountConnection.this);
         }
 
-        protected PreparedStatement prepareStatement(String sql, int rsType,
-            int rsConcur, boolean wrap) throws SQLException {
-            return new CancelPreparedStatement(super.prepareStatement(sql,
-                rsType, rsConcur, false), RefCountConnection.this);
+        protected PreparedStatement prepareStatement(String sql, int rsType, int rsConcur, boolean wrap) 
+            throws SQLException {
+            return new CancelPreparedStatement(super.prepareStatement(sql, rsType, rsConcur, false), 
+            		RefCountConnection.this);
         }
     }
 
@@ -1716,11 +1883,9 @@ public class JDBCStoreManager implements
      * Statement type that adds and removes itself from the set of active
      * statements so that it can be canceled.
      */
-    private class CancelPreparedStatement extends
-            DelegatingPreparedStatement {
+    private class CancelPreparedStatement extends DelegatingPreparedStatement {
 
-        public CancelPreparedStatement(PreparedStatement stmnt, 
-            Connection conn) {
+        public CancelPreparedStatement(PreparedStatement stmnt, Connection conn) {
             super(stmnt, conn);
         }
 

Modified: openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/FlexibleThreadLocal.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/FlexibleThreadLocal.java?rev=1240448&r1=1240447&r2=1240448&view=diff
==============================================================================
--- openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/FlexibleThreadLocal.java (original)
+++ openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/FlexibleThreadLocal.java Sat Feb  4 03:06:46 2012
@@ -18,52 +18,53 @@
  */
 package org.apache.openjpa.lib.util;
 
-import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
+
+
 /**
  * A thread-specific storage similar to {@link ThreadLocal} that 
  * <em>heuristically</em> relaxes the affinity of a value to a thread.
  * <br>
  * A thread <tt>t1</tt> can {@linkplain #set(Object) set} a value, while
  * a different thread <tt>t2</tt> can {@linkplain #get() access} the same
- * value, if <tt>t1</tt> and <tt>t2</tt> are <em>{@link #isEquivalent(Thread, Thread)
+ * value, if <tt>t1</tt> and <tt>t2</tt> are <em>{@link #eq(Object, Object)
  * equivalent}</em>.
  *  
  * @author Pinaki Poddar
  * @since 2.2.0
  */
-public class FlexibleThreadLocal<T>  {
-	private final Map<Thread, T> _values = new HashMap<Thread, T>();
+public class FlexibleThreadLocal  extends ConcurrentReferenceHashMap {
+	
+	/**
+	 * Must not hold hard reference to the threads used as keys.
+	 */
+    public FlexibleThreadLocal() {
+		super(ReferenceMap.WEAK, ReferenceMap.HARD);
+	}
 	
 	/**
-	 * Gets the value associated with the calling thread or its 
-	 * {@link #isEquivalent(Thread, Thread) equivalent}.
+	 * Gets the value associated with the calling thread or its equivalent.
 	 * 
-	 * @see #isEquivalent(Thread, Thread)
+	 * @see #eq(Object, Object)
 	 */
-	public T get() {
+	public Object get() {
 		Thread current = Thread.currentThread();
-		if (_values.containsKey(current)) {
-			return _values.get(current);
+		if (containsKey(current)) {
+			return super.get(current);
 		} else {
-			if (_values.size() == 1) {
-				return _values.values().iterator().next();
-			} else {
-				for (Map.Entry<Thread, T> e : _values.entrySet()) {
-					if (isEquivalent(e.getKey(), current))
-						return e.getValue();
-				}
-			}
-			throw new RuntimeException(current + " is not a known thread. Known threads are " + _values);
+			if (size() == 1)
+				return ((Map.Entry)entrySet().iterator().next()).getValue();
+			throw new RuntimeException(current + " is not a known thread. Known threads are " + keySet());
 		} 
 	}
 	
 	/**
 	 * Associates the value to the current thread.
 	 */
-	public T set(T t) {
-		return _values.put(Thread.currentThread(), t);
+	public void set(Object t) {
+		super.put(Thread.currentThread(), t);
 	}
 	
 	/**
@@ -75,11 +76,14 @@ public class FlexibleThreadLocal<T>  {
 	 * can equal its parent thread which is a native thread. But the parent
 	 * (native) thread is not equal to the child thread.   
 	 */
-	protected boolean isEquivalent(Thread a, Thread b) {
+	@Override
+	protected boolean eq(Object a, Object b) {
 		if (a == b) return true;
-		if (a.getThreadGroup() == b.getThreadGroup()) return true;
 		if (a == null || b == null) return false;
+		if (a instanceof Thread && b instanceof Thread) 
+			if (((Thread)a).getThreadGroup() == ((Thread)b).getThreadGroup()) 
+				return true;
 		return a.equals(b) || b.equals(a);
 	}
-
+	
 }

Added: openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/TestFlexibleThreadLocal.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/TestFlexibleThreadLocal.java?rev=1240448&view=auto
==============================================================================
--- openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/TestFlexibleThreadLocal.java (added)
+++ openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/TestFlexibleThreadLocal.java Sat Feb  4 03:06:46 2012
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agEmployee_Last_Name to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.lib.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+public class TestFlexibleThreadLocal extends TestCase {
+	private static final int MAX_THREAD = 10;
+
+	public void testCorrectValuesAreRetrievedWhenThreadsAreInSameGroup() throws Exception {
+		ExecutorService threadPool = Executors.newCachedThreadPool();
+		List<Future<?>> futures = new ArrayList<Future<?>>();
+		for (int i = 0; i < MAX_THREAD; i++) {
+			Future<?> f = threadPool.submit(new User());
+			futures.add(f);
+		}
+		waitForTermination(futures);
+		threadPool.shutdown();
+		threadPool.awaitTermination(10, TimeUnit.SECONDS);
+	}
+	
+	public void testCorrectValuesAreRetrievedWhenThreadsAreNotInSameGroup() throws Exception {
+		Thread[] threads = new Thread[MAX_THREAD];
+		for (int i = 0; i < MAX_THREAD; i++) {
+			threads[i] = new Thread(new User());
+			threads[i].start();
+		}
+		waitForTermination(threads);
+	}
+	
+
+	void waitForTermination(Thread[] threads) {
+		for (int i = 0; i < MAX_THREAD; i++) {
+			try {
+				threads[i].join();
+				threads[i].interrupt();
+			} catch (Exception e) {
+				e.printStackTrace();
+				fail(e.toString());
+			}
+		}
+	}
+	
+	void waitForTermination(List<Future<?>> futures) {
+		for (Future<?> f : futures) {
+			try {
+				f.get();
+			} catch (Exception e) {
+				e.printStackTrace();
+				fail(e.toString());
+			}
+		}
+	}
+
+}
+
+/**
+ * Sets and gets random values in a flexible thread local.
+ *
+ */
+class User implements Runnable {
+	private static final Random _rng = new Random();
+	Integer[] randoms = new Integer[20];
+	static final FlexibleThreadLocal test = new FlexibleThreadLocal();
+
+	public User() {
+		for (int i = 0; i < randoms.length; i++) {
+			randoms[i] = _rng.nextInt();
+		}
+	}
+
+	@Override
+	public void run() {
+		for (int i = 0; i < randoms.length; i++) {
+			test.set(randoms[i]);
+			try {
+				Thread.sleep(10);
+			} catch (InterruptedException e) {
+				e.printStackTrace();
+			}
+			Assert.assertEquals(Thread.currentThread() + " item " + i, randoms[i], test.get());
+		}
+	}
+
+}

Propchange: openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/TestFlexibleThreadLocal.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message