/******************************************************************************* * Copyright (c) 2005, 2015 SAP. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * SAP - initial API and implementation ******************************************************************************/ package org.eclipse.persistence.testing.tests.wdf.jpa1.lock; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.persistence.EntityManager; import javax.persistence.LockModeType; import javax.persistence.OptimisticLockException; import javax.persistence.PersistenceException; import javax.persistence.RollbackException; import javax.persistence.TransactionRequiredException; import junit.framework.Assert; import org.eclipse.persistence.testing.framework.wdf.Bugzilla; import org.eclipse.persistence.testing.framework.wdf.JPAEnvironment; import org.eclipse.persistence.testing.framework.wdf.ToBeInvestigated; import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Department; import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Hobby; import org.eclipse.persistence.testing.tests.wdf.jpa1.JPA1Base; import org.junit.Test; public class TestLockMethod extends JPA1Base { @Test public void testNonManagedEntity() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(1, "dep1"); env.beginTransaction(em); em.lock(dep, LockModeType.READ); flop("no exception NonManagedEntity"); } catch (IllegalArgumentException e) { Assert.assertTrue(true); } finally { closeEntityManager(em); } } @Test @ToBeInvestigated public void testEntityForInsert() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(1, "dep1"); env.beginTransaction(em); em.persist(dep); em.lock(dep, LockModeType.READ); flop("no exception NonManagedEntity"); } catch (IllegalArgumentException e) { Assert.assertTrue(true); } finally { closeEntityManager(em); } } @Test public void testEntityForDelete() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(100, "dep1"); env.beginTransaction(em); em.persist(dep); env.commitTransactionAndClear(em); env.beginTransaction(em); dep = em.find(Department.class, Integer.valueOf(100)); em.remove(dep); em.lock(dep, LockModeType.READ); flop("no exception NonManagedEntity"); } catch (IllegalArgumentException e) { Assert.assertTrue(true); } finally { closeEntityManager(em); } } @Test public void testEntityDeleteExecuted() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(101, "dep1"); env.beginTransaction(em); em.persist(dep); env.commitTransactionAndClear(em); env.beginTransaction(em); dep = em.find(Department.class, Integer.valueOf(101)); em.remove(dep); em.flush(); em.lock(dep, LockModeType.READ); flop("no exception NonManagedEntity"); } catch (IllegalArgumentException e) { Assert.assertTrue(true); } finally { closeEntityManager(em); } } @Test public void testNonVersionedEntity() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Hobby hobby = new Hobby("blah-muh"); env.beginTransaction(em); em.persist(hobby); env.commitTransactionAndClear(em); env.beginTransaction(em); hobby = em.merge(hobby); try { em.lock(hobby, LockModeType.READ); flop("no exception NonVersionedEntity"); } catch (IllegalArgumentException e) { Assert.assertTrue(true); } catch (PersistenceException e) { Assert.assertTrue(true); } } finally { closeEntityManager(em); } } @Test public void testIllegalArgument() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); String illegal = "pfui"; try { env.beginTransaction(em); em.lock(illegal, LockModeType.READ); flop("no exception IllegalArgument"); } catch (IllegalArgumentException iae) { Assert.assertTrue(true); } finally { closeEntityManager(em); } } @Test public void testNoTransaction() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(2, "dep2"); em.lock(dep, LockModeType.READ); flop("no exception TransactionRequired"); } catch (TransactionRequiredException tre) { Assert.assertTrue(true); } finally { closeEntityManager(em); } } @Test public void testReadLock() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(3, "dep3"); env.beginTransaction(em); em.persist(dep); env.commitTransactionAndClear(em); env.beginTransaction(em); dep = em.merge(dep); em.lock(dep, LockModeType.READ); env.commitTransaction(em); } finally { closeEntityManager(em); } } @Test public void testWriteLock() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(4, "dep4"); env.beginTransaction(em); em.persist(dep); env.commitTransactionAndClear(em); env.beginTransaction(em); dep = em.merge(dep); int version = dep.getVersion(); em.lock(dep, LockModeType.WRITE); env.commitTransaction(em); verify(dep.getVersion() > version, "version not incremented"); } finally { closeEntityManager(em); } } @Test @ToBeInvestigated public void testNewEntity() throws SQLException { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); Connection con = null; Statement stmt = null; ResultSet rs = null; try { Department dep = new Department(5, "dep5"); env.beginTransaction(em); em.persist(dep); em.lock(dep, LockModeType.READ); // verify entity is flushed to DB for locking con = env.getDataSource().getConnection(); stmt = con.createStatement(); rs = stmt.executeQuery("select count(*) from TMP_DEP where ID = 3"); rs.next(); verify(rs.getInt(1) == 1, "entity not flushed for lock"); env.commitTransaction(em); } finally { rs.close(); stmt.close(); con.close(); closeEntityManager(em); } } @Test @Bugzilla(bugid=309681) public void testLockOldVersion() { lockOldVersion(5, LockModeType.READ); lockOldVersion(6, LockModeType.WRITE); } private void lockOldVersion(int id, LockModeType lockMode) { JPAEnvironment env = getEnvironment(); EntityManager em1 = env.getEntityManagerFactory().createEntityManager(); EntityManager em2 = env.getEntityManagerFactory().createEntityManager(); Department dep1 = new Department(id, "dep" + id); try { // create entity in DB env.beginTransaction(em1); em1.persist(dep1); env.commitTransactionAndClear(em1); // read first version env.beginTransaction(em1); dep1 = em1.find(Department.class, new Integer(id)); verify(dep1 != null, "Department is null"); // change entity meanwhile env.beginTransaction(em2); Department dep2 = em2.find(Department.class, new Integer(id)); dep2.setName("dep" + id + "x"); env.commitTransactionAndClear(em2); // try to lock first version em1.lock(dep1, lockMode); env.commitTransactionAndClear(em1); flop("OptimisticLockException not thrown"); } catch (RollbackException rbe) { Throwable cause = rbe.getCause(); if (cause instanceof OptimisticLockException) { OptimisticLockException ole = (OptimisticLockException) cause; verify(dep1.equals(ole.getEntity()), "wrong entity"); } else { Assert.fail("cause is no OLE"); } } catch (OptimisticLockException ole) { verify(dep1.equals(ole.getEntity()), "wrong entity"); } finally { closeEntityManager(em1); closeEntityManager(em2); } } @Test public void testDetachedEntity() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { // case 1: detached because entity exists on db but is not known by persistence context Department dep = new Department(7, "dep7"); env.beginTransaction(em); em.persist(dep); env.commitTransaction(em); em.clear(); env.beginTransaction(em); try { em.lock(dep, LockModeType.READ); flop("exception not thrown as expected"); } catch (IllegalArgumentException e) { // $JL-EXC$ expected behavior } env.rollbackTransaction(em); em.clear(); // case 2: detached because an object with same pk but different object identity is known by persistence context // case 2a: state of known object: FOR_INSERT dep = new Department(8, "dep8"); Department depDetached = new Department(dep.getId(), "detached"); env.beginTransaction(em); em.persist(dep); try { em.lock(depDetached, LockModeType.READ); flop("exception not thrown as expected"); } catch (IllegalArgumentException e) { // $JL-EXC$ expected behavior } env.rollbackTransaction(em); em.clear(); // case 2b: state of known object: FOR_UPDATE dep = new Department(9, "dep9"); depDetached = new Department(dep.getId(), "detached"); env.beginTransaction(em); em.persist(dep); env.commitTransaction(em); em.clear(); env.beginTransaction(em); dep = em.find(Department.class, Integer.valueOf(dep.getId())); try { em.lock(depDetached, LockModeType.READ); flop("exception not thrown as expected"); } catch (IllegalArgumentException e) { // $JL-EXC$ expected behavior } env.rollbackTransaction(em); em.clear(); // case 2c: state of known object: FOR_DELETE dep = new Department(10, "dep10"); depDetached = new Department(dep.getId(), "detached"); env.beginTransaction(em); em.persist(dep); env.commitTransaction(em); em.clear(); env.beginTransaction(em); dep = em.find(Department.class, Integer.valueOf(dep.getId())); em.remove(dep); try { em.lock(depDetached, LockModeType.READ); flop("exception not thrown as expected"); } catch (IllegalArgumentException e) { // $JL-EXC$ expected behavior } env.rollbackTransaction(em); em.clear(); // case 2d: state of known object: DELETE_EXECUTED dep = new Department(11, "dep11"); depDetached = new Department(dep.getId(), "detached"); env.beginTransaction(em); em.persist(dep); env.commitTransaction(em); em.clear(); env.beginTransaction(em); dep = em.find(Department.class, Integer.valueOf(dep.getId())); em.remove(dep); em.flush(); try { em.lock(depDetached, LockModeType.READ); flop("exception not thrown as expected"); } catch (IllegalArgumentException e) { // $JL-EXC$ expected behavior } env.rollbackTransaction(em); em.clear(); } finally { closeEntityManager(em); } } @Test public void testTransactionMarkedForRollback() { final JPAEnvironment env = getEnvironment(); final EntityManager em = env.getEntityManager(); try { Department dep = new Department(12, "dep12"); env.beginTransaction(em); em.persist(dep); em.flush(); env.markTransactionForRollback(em); em.lock(dep, LockModeType.WRITE); } finally { closeEntityManager(em); } } @Test public void testReadLockTwice() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(13, "dep13"); env.beginTransaction(em); em.persist(dep); env.commitTransactionAndClear(em); env.beginTransaction(em); dep = em.merge(dep); em.lock(dep, LockModeType.READ); em.lock(dep, LockModeType.READ); env.commitTransaction(em); } finally { closeEntityManager(em); } } @Test public void testWriteLockTwice() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(14, "dep14"); env.beginTransaction(em); em.persist(dep); env.commitTransactionAndClear(em); env.beginTransaction(em); dep = em.merge(dep); em.lock(dep, LockModeType.WRITE); em.lock(dep, LockModeType.WRITE); env.commitTransaction(em); } finally { closeEntityManager(em); } } @Test public void testPromoteLock() { JPAEnvironment env = getEnvironment(); EntityManager em = env.getEntityManager(); try { Department dep = new Department(15, "dep15"); env.beginTransaction(em); em.persist(dep); env.commitTransactionAndClear(em); env.beginTransaction(em); dep = em.merge(dep); em.lock(dep, LockModeType.READ); em.lock(dep, LockModeType.WRITE); env.commitTransaction(em); } finally { closeEntityManager(em); } } }