| /* |
| * Copyright (c) 2005, 2021 Oracle and/or its affiliates. All rights reserved. |
| * 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 v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // 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 jakarta.persistence.EntityManager; |
| import jakarta.persistence.LockModeType; |
| import jakarta.persistence.OptimisticLockException; |
| import jakarta.persistence.PersistenceException; |
| import jakarta.persistence.RollbackException; |
| import jakarta.persistence.TransactionRequiredException; |
| |
| import org.junit.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, Integer.valueOf(id)); |
| verify(dep1 != null, "Department is null"); |
| // change entity meanwhile |
| env.beginTransaction(em2); |
| Department dep2 = em2.find(Department.class, Integer.valueOf(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); |
| } |
| } |
| |
| } |