You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by al...@apache.org on 2009/10/30 05:09:08 UTC

svn commit: r831194 [4/4] - in /openjpa/trunk: openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/ openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/ openjpa-p...

Added: openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/TestBasicLockScope.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/TestBasicLockScope.java?rev=831194&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/TestBasicLockScope.java (added)
+++ openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/TestBasicLockScope.java Fri Oct 30 04:09:05 2009
@@ -0,0 +1,1225 @@
+/*
+ * 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 agreed 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.persistence.lock.extended;
+
+import javax.persistence.EntityManager;
+
+/**
+ * LockScopeTestCase subclass to test entities:
+ * - with Basic attributes 
+ * - uses secondary table
+ * - uses inheritance in single table
+ * - uses inheritance and join table
+ * - uses element collection - lazy fetch (default) 
+ * - uses element collection - eager fetch 
+ */
+public class TestBasicLockScope extends LockScopeTestCase {
+
+    public void setUp() {
+        setUp(LSEBase.class
+            , LSESecTbl.class
+            , LSESngTblCon.class
+            , LSESngTblAbs.class
+            , LSEJoinCon.class
+            , LSEJoinAbs.class
+            , LSEEleCol.class
+            , LSEEleColEgr.class
+            , "openjpa.LockManager", "mixed",
+            "openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)"
+        );
+        commonSetUp(LSEBase.class
+            , LSESecTbl.class
+            , LSESngTblCon.class
+            , LSESngTblAbs.class
+            , LSEJoinCon.class
+            , LSEJoinAbs.class
+            , LSEEleCol.class
+            , LSEEleColEgr.class
+        );
+    }
+
+    public void testNormalBasicLock() {
+        commonBasicLock("testNormalBasicLock", 000, false);
+    }
+
+    public void testExtendedBasicLock() {
+        commonBasicLock("testExtendedBasicLock", 010, true);
+    }
+
+    private void commonBasicLock(String testName, int id0, boolean extended) {
+        final String tableName = "LSEBase";
+        getLog().info("** " + testName + "()");
+        String scope = extended ? "Extended" : "Normal";
+        int id1 = id0 + 1;
+
+        // create test entity.
+        LSEBase e0 = new LSEBase();
+        e0.setId(id0);
+        e0.setFirstName("firstName " + id0);
+        e0.setLastName("lastName " + id0);
+        LSEBase e1 = new LSEBase();
+        e1.setId(id1);
+        e1.setFirstName("firstName " + id1);
+        e1.setLastName("lastName " + id1);
+
+        EntityManager em = null;
+        try {
+            em = emf.createEntityManager();
+            em.getTransaction().begin();
+            em.persist(e0);
+            em.persist(e1);
+            em.getTransaction().commit();
+        } finally {
+            em = null;
+            e0 = e1 = null;
+            if (em != null && em.isOpen()) {
+                em.close();
+            }
+        }
+
+        commonLockTest(testName, LSEBase.class, id0, extended,
+                "SELECT c FROM LSEBase c WHERE c.firstName LIKE :firstName", "findLSEBase" + scope,
+                new AssertCallback() {
+                    public void findNoLockDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 0]
+                            assertLockTestSQLs(Select + tableName + Where + NoDB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? 
+                            //      [params=(int) 0]
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? 
+                            //      [params=(int) 0]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void findPessimisticForcIncDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ?
+                            //      optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1]
+                            // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ?
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1]
+                            assertLockTestSQLs(Select + tableName + Where + DB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM
+                            //     LSEBase t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1]
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? FOR UPDATE 
+                            //      [params=(int) 1]
+                            // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ? FOR UPDATE [params=(int) 1]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + ForUpdate);
+                        }
+                    }
+
+                    public void queryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%0]
+                            // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ?  [params=(int) 0]
+                            assertLockTestSQLs(Select + tableName + Where + DB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE (t0.firstName
+                            //      LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%0]
+                        case oracle:
+                            // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0 
+                            //      WHERE (t0.firstName LIKE ?) FOR UPDATE [params=(String) firstName%0]
+                            // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ? [params=(int) 0]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 1]
+                            assertLockTestSQLs(Select + tableName + Where + NoDB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ?
+                            //      [params=(int) 1]
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? 
+                            //      [params=(int) 1]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void namedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%0]
+                            // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ?  [params=(int) 0]
+                            assertLockTestSQLs(Select + tableName + Where + DB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR
+                        case oracle:
+                            // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0 
+                            //      WHERE (t0.firstName LIKE ?) FOR UPDATE [params=(String) firstName%0]
+                            // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ? [params=(int) 0]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 1]
+                            assertLockTestSQLs(Select + tableName + Where + NoDB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ?
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? 
+                            //      [params=(int) 1]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + NoForUpdate);
+                        }
+                    }
+                });
+    }
+
+    public void testNormalSecTableLock() {
+        commonSecTableLock("testNormalSecTableLock", 100, false);
+    }
+    
+    public void testExtendedSecTableLock() {
+        commonSecTableLock("testExtendedSecTableLock", 110, true); 
+    }
+
+    private void commonSecTableLock(String testName, int id0, boolean extended) {
+        final String table1Name = "LSESecTbl";
+        final String table2Name = "LSESecTblDtl";
+        final String joinTables = table1Name + ".*JOIN.*" + table2Name;
+        getLog().info("** " + testName + "()");
+        String scope = extended ? "Extended" : "Normal";
+        int id1 = id0 + 1;
+
+        // create test entity.
+        LSESecTbl e0 = new LSESecTbl();
+        e0.setId(id0);
+        e0.setFirstName("firstName " + id0);
+        e0.setLastName("lastName " + id0);
+        LSESecTbl e1 = new LSESecTbl();
+        e1.setId(id1);
+        e1.setFirstName("firstName " + id1);
+        e1.setLastName("lastName " + id1);
+
+        EntityManager em = null;
+        try {
+            em = emf.createEntityManager();
+            em.getTransaction().begin();
+            em.persist(e0);
+            em.persist(e1);
+            em.getTransaction().commit();
+        } finally {
+            em = null;
+            e0 = e1 = null;
+            if (em != null && em.isOpen()) {
+                em.close();
+            }
+        }
+
+        commonLockTest(testName, LSESecTbl.class, id0, extended,
+                "SELECT c FROM LSESecTbl c WHERE c.firstName LIKE :firstName", "findLSESecTbl" + scope,
+                new AssertCallback() {
+                    public void findNoLockDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 100]
+                            assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.LSESECTBL_ID [params=(int) 100]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ?
+                            //      [params=(int) 100]
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void findPessimisticForcIncDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ?
+                            //      optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 101]
+                            // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ?
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 101]
+                            assertLockTestSQLs(Select + joinTables + Where + DB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.LSESECTBL_ID FOR UPDATE [params=(int) 101]
+                            // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE [params=(int) 101]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate);
+                            break;
+                        case derby:     //TODO: **Non-atomic lock, SecTblDtl NOT locked *********
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ?
+                            //      [params=(int) 101]
+                            // SELECT t0.id FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 101]
+                            // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 101]
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate,
+                                    Select + table1Name + ".*" + Where + ForUpdate);
+                            break;
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + ForUpdate);
+                        }
+                    }
+
+                    public void queryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%100]
+                            // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ?  [params=(int) 100]
+                            assertLockTestSQLs(Select + joinTables + Where + DB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 
+                            //      WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSESECTBL_ID FOR UPDATE 
+                            //      [params=(String) firstName%100]
+                            // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate);
+                            break;
+                        case derby:     //TODO: **Non-atomic lock, SecTblDtl NOT locked *********
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID 
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%100]
+                            // SELECT t0.id FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 100]
+                            // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100]
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate,
+                                    Select + table1Name + ".*" + Where + ForUpdate);
+                            break;
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 101]
+                            assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.LSESECTBL_ID [params=(int) 101]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ?
+                            //      [params=(int) 101]
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void namedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%100]
+                            // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ?  [params=(int) 100]
+                            assertLockTestSQLs(Select + joinTables + Where + DB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 
+                            //      WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSESECTBL_ID FOR UPDATE 
+                            //      [params=(String) firstName%100]
+                            // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate);
+                            break;
+                        case derby:     //TODO: **Non-atomic lock, SecTblDtl NOT locked *********
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%100]
+                            // SELECT t0.id FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 100]
+                            // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100]
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate,
+                                    Select + table1Name + ".*" + Where + ForUpdate);
+                            break;
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 101]
+                            assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.LSESECTBL_ID [params=(int) 101]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0
+                            //      INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ?
+                            //      [params=(int) 101]
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate);
+                        }
+                    }
+                });
+    }
+
+    public void testNormalSingleTableLock() {
+        commonSingleTableLock("testNormalSingleTableLock", 200, false);
+    }
+    
+    public void testExtendedlSingleTableLock() {
+        commonSingleTableLock("testExtendedlSingleTableLock", 210, true);
+    }
+    
+    private void commonSingleTableLock(String testName, int id0, boolean extended) {
+        final String tableName = "LSESngTblAbs";
+        getLog().info("** " + testName + "()");
+        String scope = extended ? "Extended" : "Normal";
+        int id1 = id0 + 1;
+
+        // create test entity.
+        LSESngTblCon e0 = new LSESngTblCon();
+        e0.setId(id0);
+        e0.setFirstName("firstName " + id0);
+        e0.setLastName("lastName " + id0);
+        LSESngTblCon e1 = new LSESngTblCon();
+        e1.setId(id1);
+        e1.setFirstName("firstName " + id1);
+        e1.setLastName("lastName " + id1);
+
+        EntityManager em = null;
+        try {
+            em = emf.createEntityManager();
+            em.getTransaction().begin();
+            em.persist(e0);
+            em.persist(e1);
+            em.getTransaction().commit();
+        } finally {
+            em = null;
+            e0 = e1 = null;
+            if (em != null && em.isOpen()) {
+                em.close();
+            }
+        }
+
+        commonLockTest(testName, LSESngTblCon.class, id0, extended,
+                "SELECT c FROM LSESngTblAbs c WHERE c.firstName LIKE :firstName",
+                "findLSESngTblCon" + scope, new AssertCallback() {
+
+                    public void findNoLockDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE t0.DTYPE = ? AND t0.id = ?
+                            //      optimize for 1 row [params=(String) LSESngTblCon, (int) 200]
+                            assertLockTestSQLs(Select + tableName + Where + NoDB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 200]
+                        case oracle:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 
+                            //      WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 200]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void findPessimisticForcIncDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE t0.DTYPE = ? AND t0.id = ?
+                            //      optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS
+                            //      [params=(String) LSESngTblCon, (int) 201]
+                            // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ?
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 201]
+                            assertLockTestSQLs(Select + tableName + Where + DB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 
+                            //      WHERE t0.DTYPE = ? AND t0.id = ? FOR UPDATE WITH RR 
+                            //      [params=(String) LSESngTblCon, (int) 201]
+                            // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR
+                            //      [params=(int) 201]
+                        case oracle:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 
+                            //      WHERE t0.DTYPE = ? AND t0.id = ? FOR UPDATE 
+                            //      [params=(String) LSESngTblCon, (int) 201]
+                            // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? FOR UPDATE [params=(int) 201]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + ForUpdate);
+                        }
+                    }
+
+                    public void queryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%200]
+                            // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ?  [params=(int) 200]
+                            assertLockTestSQLs(Select + tableName + Where + DB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR
+                            //      [params=(String) firstName%200]
+                            // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200]
+                        case oracle:
+                            // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 
+                            //      WHERE (t0.firstName LIKE ?) FOR UPDATE [params=(String) firstName%200]
+                            // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE t0.DTYPE = ? AND t0.id = ?
+                            //      optimize for 1 row [params=(String) LSESngTblCon, (int) 201]
+                            assertLockTestSQLs(Select + tableName + Where + NoDB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 201]
+                        case oracle:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 
+                            //      WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 201]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void namedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\') AND t0.DTYPE = ?
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%200, (String) LSESngTblCon]
+                            // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ?  [params=(int) 200]
+                            assertLockTestSQLs(Select + tableName + Where + DB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\') AND t0.DTYPE = ? FOR UPDATE WITH RR
+                            //      [params=(String) firstName%200, (String) LSESngTblCon]
+                            // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200]
+                        case oracle:
+                            // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 
+                            //      WHERE (t0.firstName LIKE ?) AND t0.DTYPE = ? FOR UPDATE 
+                            //      [params=(String) firstName%200, (String) LSESngTblCon]
+                            // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE t0.DTYPE = ? AND t0.id = ?
+                            //      optimize for 1 row [params=(String) LSESngTblCon, (int) 201]
+                            assertLockTestSQLs(Select + tableName + Where + NoDB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0
+                            //      WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 201]
+                        case oracle:
+                            // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 
+                            //      WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 201]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + NoForUpdate);
+                        }
+                    }
+                });
+    }
+
+    public void testNormalJoinedLock() {
+        commonJoinedLock("testNormalJoinedLock", 400, false);
+    }
+    
+    public void testExtendedJoinedLock() {
+        commonJoinedLock("testExtendedJoinedLock", 410, true);
+    }
+    
+    private void commonJoinedLock(String testName, int id0, boolean extended) {
+        final String table1Name = "LSEJoinCon";
+        final String table2Name = "LSEJoinAbs";
+        final String joinTables = table1Name + ".*JOIN.*" + table2Name;
+        getLog().info("** " + testName + "()");
+        String scope = extended ? "Extended" : "Normal";
+        int id1 = id0 + 1;
+
+        // create test entity.
+        LSEJoinCon e0 = new LSEJoinCon();
+        e0.setId(id0);
+        e0.setFirstName("firstName " + id0);
+        e0.setLastName("lastName " + id0);
+        LSEJoinCon e1 = new LSEJoinCon();
+        e1.setId(id1);
+        e1.setFirstName("firstName " + id1);
+        e1.setLastName("lastName " + id1);
+
+        EntityManager em = null;
+        try {
+            em = emf.createEntityManager();
+            em.getTransaction().begin();
+            em.persist(e0);
+            em.persist(e1);
+            em.getTransaction().commit();
+        } finally {
+            em = null;
+            e0 = e1 = null;
+            if (em != null && em.isOpen()) {
+                em.close();
+            }
+        }
+
+        commonLockTest(testName, LSEJoinCon.class, id0, extended,
+                "SELECT c FROM LSEJoinCon c WHERE c.firstName LIKE :firstName", "findLSEJoinCon"
+                        + scope, new AssertCallback() {
+
+                    public void findNoLockDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 400]
+                            assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0, LSEJoinAbs t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.id [params=(int) 400]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate);
+                            break;
+                        case derby:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? [params=(int) 400]
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void findPessimisticForcIncDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ?
+                            //      optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS[params=(int) 401]
+                            // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ?
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 401]
+                            assertLockTestSQLs(Select + joinTables + Where + DB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0, LSEJoinAbs t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.id FOR UPDATE [params=(int) 401]
+                            // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE [params=(int) 401]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate);
+                            break;
+                        case derby:     //TODO: **Non-atomic lock, LSEJoinCon NOT locked *********
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? [params=(int) 401]
+                            // SELECT t0.id FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 401]
+                            // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR
+                            //      [params=(int) 401]
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate,
+                                    Select + table2Name + ".*" + Where + ForUpdate);
+                            break;
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + ForUpdate);
+                        }
+                    }
+
+                    public void queryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id
+                            //      WHERE (t1.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%400]
+                            // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ?  [params=(int) 400]
+                            assertLockTestSQLs(Select + joinTables + Where + DB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName 
+                            //      FROM LSEJoinCon t0, LSEJoinAbs t1 WHERE (t1.firstName LIKE ?) AND t0.id = t1.id 
+                            //      FOR UPDATE [params=(String) firstName%400]
+                            // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate);
+                            break;
+                        case derby:     //TODO: **Non-atomic lock, LSEJoinCon NOT locked *********
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE (t1.firstName LIKE ? ESCAPE '\')
+                            //      [params=(String) firstName%400]
+                            // SELECT t0.id FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 400]
+                            // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400]
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate,
+                                    Select + table2Name + ".*" + Where + ForUpdate);
+                            break;
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 401]
+                            assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0, LSEJoinAbs t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.id [params=(int) 401]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate);
+                            break;
+                        case derby:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? [params=(int) 401]
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void namedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id
+                            //      WHERE (t1.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%400]
+                            // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ?  [params=(int) 400]
+                            assertLockTestSQLs(Select + joinTables + Where + DB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName 
+                            //      FROM LSEJoinCon t0, LSEJoinAbs t1 WHERE (t1.firstName LIKE ?) AND t0.id = t1.id 
+                            //      FOR UPDATE [params=(String) firstName%400]
+                            // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate);
+                            break;
+                        case derby:     //TODO: **Non-atomic lock, LSEJoinCon NOT locked *********
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE (t1.firstName LIKE ? ESCAPE '\')
+                            //      [params=(String) firstName%400]
+                            // SELECT t0.id FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 400]
+                            // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400]
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate,
+                                    Select + table2Name + ".*" + Where + ForUpdate);
+                            break;
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 401]
+                            assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0, LSEJoinAbs t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.id [params=(int) 401]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate);
+                            break;
+                        case derby:
+                            // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0
+                            //      INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? [params=(int) 401]
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate);
+                        }
+                    }
+                });
+    }
+
+    public void testNormalElementCollectionLock() {
+        commonElementCollectionLock("testNormalElementCollectionLock", 500, false);
+    }
+    
+    public void testExtendedElementCollectionLock() {
+        commonElementCollectionLock("testExtendedElementCollectionLock", 510, true);
+    }
+    
+    private void commonElementCollectionLock(String testName, int id0, boolean extended) {
+        final String tableName ="LSEEleCol";
+        getLog().info("** " + testName + "()");
+        String scope = extended ? "Extended" : "Normal";
+        int id1 = id0 + 1;
+        
+        // create test entity.
+        LSEEleCol e0 = new LSEEleCol();
+        e0.setId(id0);
+        e0.setFirstName("firstName lazy " + id0);
+        e0.addCollection(id0 + "String1");
+        e0.addCollection(id0 + "String2");
+        LSEEleCol e1 = new LSEEleCol();
+        e1.setId(id1);
+        e1.setFirstName("lazy " + id1);
+        e1.addCollection(id1 + "String1");
+        e1.addCollection(id1 + "String2");
+
+        EntityManager em = null;
+        try {
+            em = emf.createEntityManager();
+            em.getTransaction().begin();
+            em.persist(e0);
+            em.persist(e1);
+            em.getTransaction().commit();
+        } finally {
+            em = null;
+            e0 = e1 = null;
+            if (em != null && em.isOpen()) {
+                em.close();
+            }
+        }
+
+        commonLockTest(testName, LSEEleCol.class, id0, extended,
+                "SELECT c FROM LSEEleCol c WHERE c.firstName LIKE :firstName", "findLSEEleCol" + scope,
+                new AssertCallback() {
+
+                    public void findNoLockDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 500]
+                            assertLockTestSQLs(Select + tableName + Where + NoDB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500]
+                        case oracle:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void findPessimisticForcIncDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ?
+                            //      optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS
+                            //      [params=(int) 501]
+                            // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ?
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 501]
+                            assertLockTestSQLs(Select + tableName + Where + DB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? FOR UPDATE WITH RR
+                            //      [params=(int) 501]
+                            // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 501]
+                        case oracle:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? FOR UPDATE 
+                            //      [params=(int) 501]
+                            // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? FOR UPDATE [params=(int) 501]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + ForUpdate);
+                        }
+                    }
+
+                    public void queryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%500]
+                            // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ?  [params=(int) 500]
+                            assertLockTestSQLs(Select + tableName + Where + DB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 WHERE
+                            //      (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%500]
+                            // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500]
+                        case oracle:
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 WHERE (t0.firstName LIKE ?) 
+                            //      FOR UPDATE [params=(String) firstName%500]
+                            // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 501]
+                            assertLockTestSQLs(Select + tableName + Where + NoDB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 501]
+                        case oracle:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 501]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void namedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%500]
+                            // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ?  [params=(int) 500]
+                            assertLockTestSQLs(Select + tableName + Where + DB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 WHERE
+                            //      (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%500]
+                            // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500]
+                        case oracle:
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 WHERE (t0.firstName LIKE ?) 
+                            //      FOR UPDATE [params=(String) firstName%500]
+                            // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ?
+                            //      optimize for 1 row [params=(int) 501]
+                            assertLockTestSQLs(Select + tableName + Where + NoDB2Lock);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 501]
+                        case oracle:
+                            // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 501]
+                        default:
+                            assertLockTestSQLs(Select + tableName + Where + NoForUpdate);
+                        }
+                    }
+                });
+    }
+
+    public void testNormalElementCollectionEagerLock() {
+        commonElementCollectionEagerLock("testNormalElementCollectionEagerLock", 600, false);
+    }
+
+    public void testExtendedElementCollectionEagerLock() {
+        commonElementCollectionEagerLock("testExtendedElementCollectionEagerLock", 610, true);
+    }
+    
+    private void commonElementCollectionEagerLock(String testName, int id0, boolean extended) {
+        final String table1Name = "LSEEleColEgr";
+        final String table2Name = "LSEEleColEgr_collection";
+//        final String table2Name_oracle = table2Name;//.toUpperCase().substring(0, Math.min(table2Name.length(), 30));
+        final String joinTables = table1Name + ".*JOIN.*" + table2Name;
+        getLog().info("** " + testName + "()");
+        String scope = extended ? "Extended" : "Normal";
+        int id1 = id0 + 1;
+
+        // create test entity.
+        LSEEleColEgr e0 = new LSEEleColEgr();
+        e0.setId(id0);
+        e0.setFirstName("firstName eager " + id0);
+        e0.addCollection(id0 + "String1");
+        e0.addCollection(id0 + "String2");
+        LSEEleColEgr e1 = new LSEEleColEgr();
+        e1.setId(id1);
+        e1.setFirstName("firstName eager " + id1);
+        e1.addCollection(id1 + "String1");
+        e1.addCollection(id1 + "String2");
+
+        EntityManager em = null;
+        try {
+            em = emf.createEntityManager();
+            em.getTransaction().begin();
+            em.persist(e0);
+            em.persist(e1);
+            em.getTransaction().commit();
+        } finally {
+            em = null;
+            e0 = e1 = null;
+            if (em != null && em.isOpen()) {
+                em.close();
+            }
+        }
+
+        commonLockTest(testName, LSEEleColEgr.class, id0, extended,
+                "SELECT c FROM LSEEleColEgr c WHERE c.firstName LIKE :firstName",
+                "findLSEEleColEgr" + scope, new AssertCallback() {
+
+                    public void findNoLockDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0
+                            //      LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID 
+                            //      WHERE t0.id = ?  [params=(int) 600]
+                            assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element 
+                            //      FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.LSEELECOLEGR_ID(+) [params=(int) 600]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + "\\(\\+\\).*"
+                                    + NoForUpdate);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0
+                            //      LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID
+                            //      WHERE t0.id = ? [params=(int) 600]
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void findPessimisticForcIncDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0
+                            //      LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID
+                            //      WHERE t0.id = ?  FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 601]
+                            // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ?
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 601]
+                            assertLockTestSQLs(Select + joinTables + Where + DB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element 
+                            //      FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.LSEELECOLEGR_ID(+) FOR UPDATE [params=(int) 601]
+                            // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? FOR UPDATE [params=(int) 601]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + "\\(\\+\\).*"
+                                    + NoForUpdate);
+                            break;
+                        case derby:     // **Non-atomic lock, No need to lock LSEEleColEgr_collection *********
+                            // TODO: Can do the same as query below, if extended scope. i.e. select LSEEleColEgr
+                            //          with lock and fetch element collection without lock.
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0
+                            //      LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID
+                            //      WHERE t0.id = ? [params=(int) 601]
+                            // SELECT t0.id FROM LSEEleColEgr t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 601]
+                            // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? FOR UPDATE WITH RR
+                            //      [params=(int) 601]
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, 
+                                    Select + table1Name + ".*" + Where + ForUpdate);
+                            break;
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + ForUpdate);
+                        }
+                    }
+
+                    public void queryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:     // **Non-atomic lock, No need to lock LSEEleColEgr_collection *********   
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%600]
+                            // SELECT t0.id, t1.element FROM LSEEleColEgr t0 INNER JOIN LSEEleColEgr_collection t1
+                            //      ON t0.id = t1.LSEELECOLEGR_ID WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      ORDER BY t0.id ASC  [params=(String) firstName%600]
+                            // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ?  [params=(int) 600]
+                            assertLockTestSQLs(Select + "LSEEleColEgr.*" + Where + DB2Lock,
+                                    Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 WHERE (t0.firstName LIKE ?) 
+                            //      FOR UPDATE [params=(String) firstName%600]
+                            // SELECT t0.id, t1.element FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 
+                            //      WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSEELECOLEGR_ID ORDER BY t0.id ASC 
+                            //      FOR UPDATE [params=(String) firstName%600]
+                            // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate);
+                            break;
+                        case derby:     //**Non-atomic lock, No need to lock LSEEleColEgr_Collection *********
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 WHERE
+                            //      (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%600]
+                            // SELECT t0.id, t1.element FROM LSEEleColEgr t0 INNER JOIN LSEEleColEgr_collection t1 
+                            //      ON t0.id = t1.LSEELECOLEGR_ID WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      ORDER BY t0.id ASC [params=(String) firstName%600]
+                            // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600]
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate,
+                                    Select + table1Name + ".*" + Where + ForUpdate);
+                            break;
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0
+                            //      LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID
+                            //      WHERE t0.id = ?  [params=(int) 601]
+                            assertLockTestSQLs(Select + "LSEEleColEgr.*" + Where + DB2Lock,
+                                    Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element 
+                            //      FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.LSEELECOLEGR_ID(+) [params=(int) 601]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + "\\(\\+\\).*"
+                                    + NoForUpdate);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0
+                            //      LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID
+                            //      WHERE t0.id = ? [params=(int) 601]
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate);
+                        }
+                    }
+
+                    public void namedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {
+                        case db2:     // **Non-atomic lock, No need to lock LSEEleColEgr_collection *********   
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0
+                            //      WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%600]
+                            // SELECT t0.id, t1.element FROM LSEEleColEgr t0 INNER JOIN LSEEleColEgr_collection t1
+                            //      ON t0.id = t1.LSEELECOLEGR_ID WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      ORDER BY t0.id ASC  [params=(String) firstName%600]
+                            // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ?  [params=(int) 600]
+                            assertLockTestSQLs(Select + "LSEEleColEgr.*" + Where + DB2Lock,
+                                    Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 WHERE (t0.firstName LIKE ?) 
+                            //      FOR UPDATE [params=(String) firstName%600]
+                            // SELECT t0.id, t1.element FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 
+                            //      WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSEELECOLEGR_ID ORDER BY t0.id ASC 
+                            //      FOR UPDATE [params=(String) firstName%600]
+                            // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate);
+                            break;
+                        case derby:     // **Non-atomic lock, No need to lock LSEEleColEgr_collection *********   
+                            // The database is unable to lock this query.  Each object matching the query will be 
+                            //  locked individually after it is loaded; however, it is technically possible that
+                            //  another transaction could modify the data before the lock is obtained.
+                            // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 WHERE
+                            //      (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%600]
+                            // SELECT t0.id, t1.element FROM LSEEleColEgr t0 INNER JOIN LSEEleColEgr_collection t1
+                            //      ON t0.id = t1.LSEELECOLEGR_ID WHERE (t0.firstName LIKE ? ESCAPE '\')
+                            //      ORDER BY t0.id ASC [params=(String) firstName%600]
+                            // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600]
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, 
+                                    Select + table1Name + ".*" + Where + ForUpdate);
+                            break;
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + ForUpdate);
+                        }
+                    }
+
+                    public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) {
+                        switch (getDBType(em)) {    // **Check
+                        case db2:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0 
+                            //      LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID
+                            //      WHERE t0.id = ?  [params=(int) 601]
+                            assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock);
+                            break;
+                        case oracle:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element 
+                            //      FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 
+                            //      WHERE t0.id = ? AND t0.id = t1.LSEELECOLEGR_ID(+) [params=(int) 601]
+                            assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + "\\(\\+\\).*"
+                                    + NoForUpdate);
+                            break;
+                        case derby:
+                            // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0
+                            //      LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID
+                            //      WHERE t0.id = ? [params=(int) 601]
+                        default:
+                            assertLockTestSQLs(Select + joinTables + Where + NoForUpdate);
+                        }
+                    }
+                });
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/TestBasicLockScope.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java?rev=831194&r1=831193&r2=831194&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java Fri Oct 30 04:09:05 2009
@@ -61,8 +61,6 @@
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 
-import javax.persistence.Access;
-import javax.persistence.AccessType;
 import javax.persistence.Id;
 import javax.persistence.IdClass;
 import javax.persistence.Lob;
@@ -1772,7 +1770,9 @@
             meta.setLanguage(JPQLParser.LANG_JPQL);
             for (QueryHint hint : query.hints())
                 meta.addHint(hint.name(), hint.value());
-
+            if (query.lockMode() != null) {
+                meta.addHint("openjpa.FetchPlan.ReadLockMode", query.lockMode());
+            }
             meta.setSource(getSourceFile(), (el instanceof Class) ? el : null,
                 SourceTracker.SRC_ANNOTATIONS);
             if (isMetaDataMode())

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java?rev=831194&r1=831193&r2=831194&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java Fri Oct 30 04:09:05 2009
@@ -20,9 +20,9 @@
 
 import java.util.Collection;
 import java.util.Map;
-import java.util.Set;
 
 import javax.persistence.LockModeType;
+import javax.persistence.PessimisticLockScope;
 
 import org.apache.openjpa.kernel.DataCacheRetrieveMode;
 import org.apache.openjpa.kernel.DataCacheStoreMode;
@@ -322,6 +322,16 @@
     public FetchPlan setLockTimeout(int timeout);
 
     /**
+     * The lock scope to use for locking loaded objects.
+     */
+    public PessimisticLockScope getLockScope();
+
+    /**
+     * The lock scope to use for locking loaded objects.
+     */
+    public FetchPlan setLockScope(PessimisticLockScope scope);
+
+    /**
      * The number of milliseconds to wait for a query, or -1 for no
      * limit.
      */

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanHintHandler.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanHintHandler.java?rev=831194&r1=831193&r2=831194&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanHintHandler.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanHintHandler.java Fri Oct 30 04:09:05 2009
@@ -59,6 +59,7 @@
         }
         // Initialize javax.persistence to openjpa.FetchPlan hint mapping.
         javaxHintsMap.put(JPAProperties.LOCK_TIMEOUT,  PREFIX_FETCHPLAN + "LockTimeout");
+        javaxHintsMap.put(JPAProperties.LOCK_SCOPE,    PREFIX_FETCHPLAN + "LockScope");
         javaxHintsMap.put(JPAProperties.QUERY_TIMEOUT, PREFIX_FETCHPLAN + "QueryTimeout");
         // Initialize hint precedence order mapping from list.
         String[][] precedenceMapList = {
@@ -66,6 +67,10 @@
               PREFIX_FETCHPLAN  + "LockTimeout",
               PREFIX_OPENJPA    + "LockTimeout" },
 
+            { JPAProperties.LOCK_SCOPE,
+              PREFIX_FETCHPLAN  + "LockScope",
+              PREFIX_OPENJPA    + "LockScope" },
+
             { JPAProperties.QUERY_TIMEOUT,
               PREFIX_FETCHPLAN  + "QueryTimeout",
               PREFIX_OPENJPA    + "QueryTimeout" },

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java?rev=831194&r1=831193&r2=831194&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java Fri Oct 30 04:09:05 2009
@@ -25,6 +25,7 @@
 import java.util.Map;
 
 import javax.persistence.LockModeType;
+import javax.persistence.PessimisticLockScope;
 
 import org.apache.openjpa.kernel.DataCacheRetrieveMode;
 import org.apache.openjpa.kernel.DataCacheStoreMode;
@@ -237,6 +238,15 @@
         return this;
     }
 
+    public PessimisticLockScope getLockScope() {
+        return LockScopesHelper.fromLockScope(_fetch.getLockScope());
+    }
+
+    public FetchPlan setLockScope(PessimisticLockScope scope) {
+        _fetch.setLockScope(LockScopesHelper.toLockScope(scope));
+        return this;
+    }
+
     public int getQueryTimeout() {
         return _fetch.getQueryTimeout();
     }

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/LockScopesHelper.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/LockScopesHelper.java?rev=831194&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/LockScopesHelper.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/LockScopesHelper.java Fri Oct 30 04:09:05 2009
@@ -0,0 +1,49 @@
+/*
+ * 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 agreed 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.persistence;
+
+import javax.persistence.PessimisticLockScope;
+
+import org.apache.openjpa.kernel.LockScopes;
+
+/**
+ * Helper methods translate between JPA-defined pessimistic lock scope and
+ * OpenJPA internal lock scope levels.
+ * 
+ * @since 2.0.0
+ */
+public class LockScopesHelper {
+    /**
+     * Translates javax.persistence LockModeType to internal lock level.
+     */
+    public static int toLockScope(PessimisticLockScope scope) {
+        if (scope == null || scope == PessimisticLockScope.NORMAL)
+            return LockScopes.LOCKSCOPE_NORMAL;
+        return LockScopes.LOCKSCOPE_EXTENDED;
+    }
+
+    /**
+     * Translates internal lock level to javax.persistence LockModeType.
+     */
+    public static PessimisticLockScope fromLockScope(int level) {
+        if (level < LockScopes.LOCKSCOPE_EXTENDED)
+            return PessimisticLockScope.NORMAL;
+        return PessimisticLockScope.EXTENDED;
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/LockScopesHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java?rev=831194&r1=831193&r2=831194&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java Fri Oct 30 04:09:05 2009
@@ -31,15 +31,14 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.Stack;
+
 import javax.persistence.CascadeType;
 import javax.persistence.GenerationType;
+import javax.persistence.LockModeType;
 
 import static javax.persistence.CascadeType.*;
 
 import org.apache.commons.lang.StringUtils;
-import org.xml.sax.Attributes;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.enhance.PersistenceCapable;
 import org.apache.openjpa.event.BeanLifecycleCallbacks;
@@ -61,7 +60,6 @@
 import org.apache.openjpa.meta.JavaTypes;
 import org.apache.openjpa.meta.LifecycleMetaData;
 import org.apache.openjpa.meta.MetaDataContext;
-import org.apache.openjpa.meta.MetaDataDefaults;
 import org.apache.openjpa.meta.MetaDataFactory;
 import static org.apache.openjpa.meta.MetaDataModes.*;
 import org.apache.openjpa.meta.MetaDataRepository;
@@ -73,6 +71,9 @@
 import static org.apache.openjpa.persistence.PersistenceStrategy.*;
 import org.apache.openjpa.util.ImplHelper;
 import org.apache.openjpa.util.MetaDataException;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
 
 import serp.util.Numbers;
 
@@ -1106,7 +1107,7 @@
         throws SAXException {
         FieldMetaData fmd = (FieldMetaData) currentElement();
         int typeCode = fmd.isElementCollection() ? fmd.getElement().getDeclaredTypeCode() : fmd.getDeclaredTypeCode();
-        Class type = fmd.isElementCollection() ? fmd.getElement().getDeclaredType() : fmd.getDeclaredType();
+        Class<?> type = fmd.isElementCollection() ? fmd.getElement().getDeclaredType() : fmd.getDeclaredType();
         if (typeCode != JavaTypes.STRING
             && type != char[].class
             && type != Character[].class
@@ -1651,12 +1652,10 @@
         meta.setDefiningType(_cls);
         meta.setQueryString(attrs.getValue("query"));
         meta.setLanguage(JPQLParser.LANG_JPQL);
-        /** TODO: Uncomment when orm.xsd defines lockmode
-        LockModeType lockMode =
-                 LockModeType.valueOf(attrs.getValue("lockMode"));
-        meta.addHint("openjpa.FetchPlan.ReadLockMode",
-            JPA2LockLevels.toLockLevel(lockMode));
-        **/
+        String lockModeStr = attrs.getValue("lock-mode");
+        if (lockModeStr != null) {
+            meta.addHint("openjpa.FetchPlan.ReadLockMode", LockModeType.valueOf(lockModeStr));
+        }
         Locator locator = getLocation().getLocator();
         if (locator != null) {
             meta.setLineNumber(Numbers.valueOf(locator.getLineNumber()));