blob: daee91e131ace28349f6ad1dea17b5c0fae74f7a [file] [log] [blame]
/*
* 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.lockmgr;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.TransactionRequiredException;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfigurationImpl;
import org.apache.openjpa.jdbc.sql.DB2Dictionary;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.persistence.EntityManagerImpl;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
/**
* Test hints using EntityManager interface.
*/
public class TestEmLockMode extends SequencedActionsTest {
private static String NON_SUPPORTED_OPTIMISTIC_SQL =
"SELECT .* FROM LockEmployee .*";
private static String NON_SUPPORTED_FOR_UPDATE_SQL = "" ; // append lock clause from dict
private static String VERSION_UPDATE_SQL =
"UPDATE LockEmployee SET version .* WHERE .*";
private static String DB2_OPTIMISTIC_SQL =
"SELECT .* FROM LockEmployee .* WHERE .*";
private static String DB2_PESSIMISTIC_RS_SQL =
"SELECT .* FROM LockEmployee .* WITH RS USE .*";
private static String DB2_PESSIMISTIC_RR_SQL =
"SELECT .* FROM LockEmployee .* WITH RR USE .*";
public void setUp() {
setUp(LockEmployee.class, "openjpa.LockManager", "mixed");
commonSetUp();
NON_SUPPORTED_FOR_UPDATE_SQL = NON_SUPPORTED_OPTIMISTIC_SQL + " " + escapeRegex(getForUpdateClause()) + ".*";
}
private String escapeRegex(String clause) {
// escape an update clause for use in a regex.
// only handling ( ) for now
String rval = clause.replace("(", "\\(");
rval = rval.replace(")", "\\)");
return rval;
}
/*
* Test em.find(lockmode);
*/
public void testFindLockModeIsolations() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
commonTestFindLockModeIsolations(em, LockModeType.NONE, 1,
DB2_OPTIMISTIC_SQL, 1, NON_SUPPORTED_OPTIMISTIC_SQL, 0, null);
commonTestFindLockModeIsolations(em, LockModeType.READ, 1,
DB2_OPTIMISTIC_SQL, 1, NON_SUPPORTED_OPTIMISTIC_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestFindLockModeIsolations(em, LockModeType.WRITE, 1,
DB2_OPTIMISTIC_SQL, 1, NON_SUPPORTED_OPTIMISTIC_SQL, 1,
VERSION_UPDATE_SQL);
commonTestFindLockModeIsolations(em, LockModeType.OPTIMISTIC, 1,
DB2_OPTIMISTIC_SQL, 1, NON_SUPPORTED_OPTIMISTIC_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestFindLockModeIsolations(em,
LockModeType.OPTIMISTIC_FORCE_INCREMENT, 1, DB2_OPTIMISTIC_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL, 1, VERSION_UPDATE_SQL);
commonTestFindLockModeIsolations(em, LockModeType.PESSIMISTIC_READ, 2,
DB2_PESSIMISTIC_RS_SQL, 2, NON_SUPPORTED_FOR_UPDATE_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestFindLockModeIsolations(em, LockModeType.PESSIMISTIC_WRITE, 2,
DB2_PESSIMISTIC_RR_SQL, 2, NON_SUPPORTED_FOR_UPDATE_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestFindLockModeIsolations(em,
LockModeType.PESSIMISTIC_FORCE_INCREMENT, 2,
DB2_PESSIMISTIC_RR_SQL, 2, NON_SUPPORTED_FOR_UPDATE_SQL, 1,
VERSION_UPDATE_SQL);
em.getTransaction().rollback();
em.close();
}
private void commonTestFindLockModeIsolations(EntityManager em,
LockModeType lockMode, int expectedSupportSQLCount,
String expectedSupportSQL, int expectedNonSupportSQLCount,
String expectedNonSupportSQL, int expectedVersionUpdateCount,
String expectedVersionUpdateSQL) {
OpenJPAEntityManager oem = (OpenJPAEntityManager) em.getDelegate();
JDBCFetchConfigurationImpl fConfig = (JDBCFetchConfigurationImpl)
((EntityManagerImpl) oem).getBroker().getFetchConfiguration();
DBDictionary dict = ((JDBCConfiguration) ((OpenJPAEntityManagerSPI) oem)
.getConfiguration()).getDBDictionaryInstance();
em.clear();
resetSQL();
int beforeIsolation = fConfig.getIsolation();
em.find(LockEmployee.class, 1, lockMode);
if (dict.supportsIsolationForUpdate() &&
dict instanceof DB2Dictionary) {
assertEquals(expectedSupportSQLCount, getSQLCount());
assertAllSQLInOrder(expectedSupportSQL);
} else {
assertEquals(expectedNonSupportSQLCount, getSQLCount());
assertAllSQLInOrder(expectedNonSupportSQL);
}
resetSQL();
em.flush();
assertEquals(expectedVersionUpdateCount, getSQLCount());
if (expectedVersionUpdateSQL != null)
assertAllSQLInOrder(expectedVersionUpdateSQL);
assertEquals(beforeIsolation, fConfig.getIsolation());
}
/*
* Test em.refresh(lockmode);
*/
public void testRefreshLockModeIsolations() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
commonTestRefreshLockModeIsolations(em, LockModeType.NONE, 1,
DB2_OPTIMISTIC_SQL, 1, NON_SUPPORTED_OPTIMISTIC_SQL, 0, null);
commonTestRefreshLockModeIsolations(em, LockModeType.READ, 1,
DB2_OPTIMISTIC_SQL, 1, NON_SUPPORTED_OPTIMISTIC_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestRefreshLockModeIsolations(em, LockModeType.WRITE, 1,
DB2_OPTIMISTIC_SQL, 1, NON_SUPPORTED_OPTIMISTIC_SQL, 1,
VERSION_UPDATE_SQL);
commonTestRefreshLockModeIsolations(em, LockModeType.OPTIMISTIC, 1,
DB2_OPTIMISTIC_SQL, 1, NON_SUPPORTED_OPTIMISTIC_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestRefreshLockModeIsolations(em,
LockModeType.OPTIMISTIC_FORCE_INCREMENT, 1, DB2_OPTIMISTIC_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL, 1, VERSION_UPDATE_SQL);
commonTestRefreshLockModeIsolations(em, LockModeType.PESSIMISTIC_READ,
2, DB2_PESSIMISTIC_RS_SQL, 2, NON_SUPPORTED_FOR_UPDATE_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestRefreshLockModeIsolations(em, LockModeType.PESSIMISTIC_WRITE,
2, DB2_PESSIMISTIC_RR_SQL, 2, NON_SUPPORTED_FOR_UPDATE_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestRefreshLockModeIsolations(em,
LockModeType.PESSIMISTIC_FORCE_INCREMENT, 2,
DB2_PESSIMISTIC_RR_SQL, 2, NON_SUPPORTED_FOR_UPDATE_SQL, 1,
VERSION_UPDATE_SQL);
em.getTransaction().rollback();
em.close();
}
private void commonTestRefreshLockModeIsolations(EntityManager em,
LockModeType lockMode, int expectedSupportSQLCount,
String expectedSupportSQL, int expectedNonSupportSQLCount,
String expectedNonSupportSQL, int expectedVersionUpdateCount,
String expectedVersionUpdateSQL) {
OpenJPAEntityManager oem = (OpenJPAEntityManager) em.getDelegate();
JDBCFetchConfigurationImpl fConfig = (JDBCFetchConfigurationImpl)
((EntityManagerImpl) oem).getBroker().getFetchConfiguration();
DBDictionary dict = ((JDBCConfiguration) ((OpenJPAEntityManagerSPI) oem)
.getConfiguration()).getDBDictionaryInstance();
em.clear();
LockEmployee employee = em.find(LockEmployee.class, 1);
resetSQL();
int beforeIsolation = fConfig.getIsolation();
em.refresh(employee, lockMode);
if (dict.supportsIsolationForUpdate() &&
dict instanceof DB2Dictionary) {
assertEquals(expectedSupportSQLCount, getSQLCount());
assertAllSQLInOrder(expectedSupportSQL);
} else {
assertEquals(expectedNonSupportSQLCount, getSQLCount());
assertAllSQLInOrder(expectedNonSupportSQL);
}
resetSQL();
em.flush();
assertEquals(expectedVersionUpdateCount, getSQLCount());
if (expectedVersionUpdateSQL != null)
assertAllSQLInOrder(expectedVersionUpdateSQL);
assertEquals(beforeIsolation, fConfig.getIsolation());
}
/*
* Test em.lock(lockmode);
*/
public void testLockLockModeIsolations() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
commonTestLockLockModeIsolations(em, LockModeType.NONE, 0, null, 0,
null, 0, null);
commonTestLockLockModeIsolations(em, LockModeType.READ, 0, null, 0,
null, 1, NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestLockLockModeIsolations(em, LockModeType.WRITE, 0, null, 0,
null, 1, VERSION_UPDATE_SQL);
commonTestLockLockModeIsolations(em, LockModeType.OPTIMISTIC, 0, null,
0, null, 1, NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestLockLockModeIsolations(em,
LockModeType.OPTIMISTIC_FORCE_INCREMENT, 0, null, 0, null, 1,
VERSION_UPDATE_SQL);
commonTestLockLockModeIsolations(em, LockModeType.PESSIMISTIC_READ, 2,
DB2_PESSIMISTIC_RS_SQL, 2, NON_SUPPORTED_FOR_UPDATE_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestLockLockModeIsolations(em, LockModeType.PESSIMISTIC_WRITE, 2,
DB2_PESSIMISTIC_RR_SQL, 2, NON_SUPPORTED_FOR_UPDATE_SQL, 1,
NON_SUPPORTED_OPTIMISTIC_SQL);
commonTestLockLockModeIsolations(em,
LockModeType.PESSIMISTIC_FORCE_INCREMENT, 2,
DB2_PESSIMISTIC_RR_SQL, 2, NON_SUPPORTED_FOR_UPDATE_SQL, 1,
VERSION_UPDATE_SQL);
em.getTransaction().rollback();
em.close();
}
private void commonTestLockLockModeIsolations(EntityManager em,
LockModeType lockMode, int expectedSupportSQLCount,
String expectedSupportSQL, int expectedNonSupportSQLCount,
String expectedNonSupportSQL, int expectedVersionUpdateCount,
String expectedVersionUpdateSQL) {
OpenJPAEntityManager oem = (OpenJPAEntityManager) em.getDelegate();
JDBCFetchConfigurationImpl fConfig = (JDBCFetchConfigurationImpl)
((EntityManagerImpl) oem).getBroker().getFetchConfiguration();
DBDictionary dict = ((JDBCConfiguration) ((OpenJPAEntityManagerSPI) oem)
.getConfiguration()).getDBDictionaryInstance();
em.clear();
LockEmployee employee = em.find(LockEmployee.class, 1);
resetSQL();
int beforeIsolation = fConfig.getIsolation();
em.lock(employee, lockMode);
if (dict.supportsIsolationForUpdate() &&
dict instanceof DB2Dictionary) {
assertEquals(expectedSupportSQLCount, getSQLCount());
if (expectedSupportSQL != null)
assertAllSQLInOrder(expectedSupportSQL);
} else {
assertEquals(expectedNonSupportSQLCount, getSQLCount());
if (expectedNonSupportSQL != null)
assertAllSQLInOrder(expectedNonSupportSQL);
}
resetSQL();
em.flush();
assertEquals(expectedVersionUpdateCount, getSQLCount());
if (expectedVersionUpdateSQL != null)
assertAllSQLInOrder(expectedVersionUpdateSQL);
assertEquals(beforeIsolation, fConfig.getIsolation());
}
/*
* Test em.getLockMode();
*/
public void testGetLockMode() {
EntityManager em = emf.createEntityManager();
LockEmployee employee = em.find(LockEmployee.class, 1);
try {
em.getLockMode(employee);
fail("Expecting TransactionRequiredException.");
} catch (TransactionRequiredException tre) {
} catch (Exception e){
fail("Expecting TransactionRequiredException.");
}
em.getTransaction().begin();
try {
assertEquals("getLockMode only allows in transaction.",LockModeType.NONE, em.getLockMode(employee));
} catch (Exception e){
fail("Do not expecting any exception.");
}
em.getTransaction().rollback();
em.clear();
em.getTransaction().begin();
try {
// getLockMode on a detached entity;
em.getLockMode(employee);
fail("Expecting IllegalArgumentException for getLockMode on a detached entity in an active transaction.");
} catch (IllegalArgumentException iae) {
} catch (Exception e){
fail("Expecting IllegalArgumentException for getLockMode on a detached entity in an active transaction.");
}
em.getTransaction().rollback();
em.getTransaction().begin();
try {
employee = em.find(LockEmployee.class, 1, LockModeType.PESSIMISTIC_WRITE);
assertEquals("Test getLockMode on non-NONE lock mode type.", LockModeType.PESSIMISTIC_WRITE, em
.getLockMode(employee));
} catch (Exception e){
fail("Do not expecting any exception.");
}
em.getTransaction().rollback();
em.close();
}
}