alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (LockTest.java)

This example Hibernate source code file (LockTest.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

bg, bg, countdownlatch, entitymanager, entitymanager, exception, futuretask, integer, lock, lock, locktimeoutexception, test, test, thread, threading, threads, util

The Hibernate LockTest.java source code

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.hibernate.ejb.test.lock;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.LockTimeoutException;
import javax.persistence.OptimisticLockException;
import javax.persistence.Query;
import javax.persistence.QueryTimeoutException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

import org.jboss.logging.Logger;

import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.ejb.AvailableSettings;
import org.hibernate.ejb.test.BaseEntityManagerFunctionalTestCase;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

/**
 * @author Emmanuel Bernard
 */
public class LockTest extends BaseEntityManagerFunctionalTestCase {
	private static final Logger log = Logger.getLogger( LockTest.class );

	@Test
	public void testFindWithTimeoutHint() {
		EntityManager em = getOrCreateEntityManager();
		em.getTransaction().begin();
		Lock lock = new Lock();
		lock.setName( "name" );
		em.persist( lock );
		em.getTransaction().commit();
		em.close();

		em = getOrCreateEntityManager();
		em.getTransaction().begin();
		Map<String, Object> properties = new HashMap();
		properties.put( AvailableSettings.LOCK_TIMEOUT, 0L );
		em.find( Lock.class, 1, LockModeType.PESSIMISTIC_WRITE, properties );
		em.getTransaction().commit();
		em.close();

		em = getOrCreateEntityManager();
		em.getTransaction().begin();
		lock = em.find( Lock.class, lock.getId() );
		em.remove( lock );
		em.getTransaction().commit();
		em.close();
	}

	@Test
	public void testLockRead() throws Exception {
		Lock lock = new Lock();
		lock.setName( "name" );
		EntityManager em = getOrCreateEntityManager();
		em.getTransaction().begin();
		em.persist( lock );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( Lock.class, lock.getId() );
		em.lock( lock, LockModeType.READ );
		lock.setName( "surname" );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.find( Lock.class, lock.getId() );
		assertEquals( "surname", lock.getName() );
		em.remove( lock );
		em.getTransaction().commit();

		em.close();
	}

	@Test
	public void testLockOptimistic() throws Exception {
		Lock lock = new Lock();
		lock.setName( "name" );
		EntityManager em = getOrCreateEntityManager();
		em.getTransaction().begin();
		em.persist( lock );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( Lock.class, lock.getId() );
		em.lock( lock, LockModeType.OPTIMISTIC );
		lock.setName( "surname" );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.find( Lock.class, lock.getId() );
		assertEquals( "surname", lock.getName() );
		em.remove( lock );
		em.getTransaction().commit();

		em.close();
	}

	@Test
	public void testLockWrite() throws Exception {
		Lock lock = new Lock();
		lock.setName( "second" );
		EntityManager em = getOrCreateEntityManager();
		em.getTransaction().begin();
		em.persist( lock );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( Lock.class, lock.getId() );
		Integer version = lock.getVersion();
		em.lock( lock, LockModeType.WRITE );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( Lock.class, lock.getId() );
		try {
			assertEquals( "should increase the version number EJB-106", 1, lock.getVersion() - version );
		}
		finally {
			em.remove( lock );
			em.getTransaction().commit();
		}
		em.close();
	}

	@Test
	public void testLockWriteOnUnversioned() throws Exception {
		UnversionedLock lock = new UnversionedLock();
		lock.setName( "second" );
		EntityManager em = getOrCreateEntityManager();
		em.getTransaction().begin();
		em.persist( lock );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( UnversionedLock.class, lock.getId() );
		try {
			// getting a READ (optimistic) lock on unversioned entity is not expected to work.
			// To get the same functionality as prior release, change the  LockModeType.READ lock to:
			// em.lock(lock,LockModeType.PESSIMISTIC_READ);
			em.lock( lock, LockModeType.READ );
			fail("expected OptimisticLockException exception");
		} catch(OptimisticLockException expected) {}
		em.getTransaction().rollback();

		// the previous code block can be rewritten as follows (to get the previous behavior)
		em.getTransaction().begin();
		lock = em.getReference( UnversionedLock.class, lock.getId() );
		em.lock( lock, LockModeType.PESSIMISTIC_READ );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( UnversionedLock.class, lock.getId() );
		em.remove( lock );
		em.getTransaction().commit();
		em.close();
	}

	@Test
	public void testLockPessimisticForceIncrement() throws Exception {
		Lock lock = new Lock();
		lock.setName( "force" );
		EntityManager em = getOrCreateEntityManager();
		em.getTransaction().begin();
		em.persist( lock );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( Lock.class, lock.getId() );
		Integer version = lock.getVersion();
		em.lock( lock, LockModeType.PESSIMISTIC_FORCE_INCREMENT );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( Lock.class, lock.getId() );
		try {
			assertEquals( "should increase the version number ", 1, lock.getVersion() - version );
		}
		finally {
			em.remove( lock );
			em.getTransaction().commit();
		}
		em.close();
	}

	@Test
	public void testLockOptimisticForceIncrement() throws Exception {
		Lock lock = new Lock();
		lock.setName( "force" );
		EntityManager em = getOrCreateEntityManager();
		em.getTransaction().begin();
		em.persist( lock );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( Lock.class, lock.getId() );
		Integer version = lock.getVersion();
		em.lock( lock, LockModeType.OPTIMISTIC_FORCE_INCREMENT );
		em.getTransaction().commit();

		em.getTransaction().begin();
		lock = em.getReference( Lock.class, lock.getId() );
		try {
			assertEquals( "should increase the version number ", 1, lock.getVersion() - version );
		}
		finally {
			em.remove( lock );
			em.getTransaction().commit();
		}
		em.close();
	}

	@Test
	public void testLockOptimisticForceIncrementDifferentEm() throws Exception {
		Lock lock = new Lock();
		lock.setName( "force" );
		EntityManager em1 = createIsolatedEntityManager();
		em1.getTransaction().begin();
		em1.persist( lock );
		em1.getTransaction().commit();
		em1.close();

		EntityManager em2 = createIsolatedEntityManager();
		em2.getTransaction().begin();
		lock = em2.find( Lock.class, lock.getId(), LockModeType.OPTIMISTIC );
		assertEquals( "lock mode should be OPTIMISTIC ", LockModeType.OPTIMISTIC, em2.getLockMode(lock) );
		em2.lock( lock, LockModeType.OPTIMISTIC_FORCE_INCREMENT );
		assertEquals( "lock mode should be OPTIMISTIC_FORCE_INCREMENT ", LockModeType.OPTIMISTIC_FORCE_INCREMENT, em2.getLockMode(lock) );
		em2.getTransaction().commit();
		em2.getTransaction().begin();
		em2.remove( lock );
		em2.getTransaction().commit();
		em2.close();
	}

	@Test
	public void testContendedPessimisticLock() throws Exception {
		EntityManager em = getOrCreateEntityManager();
		final EntityManager em2 = createIsolatedEntityManager();
		// TODO:  replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticWriteLock)
		if ( getDialect() instanceof HSQLDialect) {
            log.info("skipping testContendedPessimisticLock");
			return;
		}
		Lock lock = new Lock();
		Thread t = null;
		try {
			lock.setName( "testContendedPessimisticLock" );

			em.getTransaction().begin();
			em.persist( lock );
			em.getTransaction().commit();
			em.clear();

			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
			final Integer id = lock.getId();
			lock.getName();		// force entity to be read
            log.info("testContendedPessimisticLock: got write lock");
			final CountDownLatch latch = new CountDownLatch(1);

			t = new Thread( new Runnable() {
				public void run() {
					try {
						em2.getTransaction().begin();
                        log.info("testContendedPessimisticLock: (BG) about to issue (PESSIMISTIC_READ) query against write-locked entity");
						// we should block on the following read
						Query query = em2.createQuery(
								  "select L from Lock_ L where L.id < 10000 ");
						query.setLockMode(LockModeType.PESSIMISTIC_READ);
						List<Lock> resultList = query.getResultList();
						resultList.get(0).getName(); //  force entity to be read
					}
					finally {
						em2.getTransaction().commit();
						latch.countDown();	// signal that we got the read lock
					}
				}
			} );

			t.setDaemon( true );
			t.setName("LockTest read lock");
			t.start();
            log.info("testContendedPessimisticLock:  wait on BG thread");
			boolean latchSet = latch.await( 10, TimeUnit.SECONDS );
			// latchSet should be false (timeout) because the background thread
			// shouldn't be able to get a read lock on write locked entity.
            log.info("testContendedPessimisticLock:  BG thread completed transaction");
			assertFalse( "shouldn't be able to get read lock while another transaction has write lock",latchSet );
			em.getTransaction().commit();
		}
		finally {
			if ( em.getTransaction().isActive() ) {
				em.getTransaction().rollback();
			}
			if ( t != null) {	  // wait for background thread to finish before deleting entity
				t.join();
			}
			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.remove( lock );
			em.getTransaction().commit();
			em.close();
			em2.close();
		}
	}

	@Test
	public void testContendedPessimisticReadLockTimeout() throws Exception {
		EntityManager em = getOrCreateEntityManager();
		final EntityManager em2 = createIsolatedEntityManager();
		// TODO:  replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticLockTimeout)
		if ( ! (getDialect() instanceof Oracle10gDialect)) {
            log.info("skipping testContendedPessimisticReadLockTimeout");
			return;
		}
		Lock lock = new Lock();
		Thread t = null;
		FutureTask<Boolean> bgTask = null;
		final CountDownLatch latch = new CountDownLatch(1);
		try {
			lock.setName( "testContendedPessimisticReadLockTimeout" );

			em.getTransaction().begin();
			em.persist( lock );
			em.getTransaction().commit();
			em.clear();

			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
			final Integer id = lock.getId();
			lock.getName();		// force entity to be read
            log.info("testContendedPessimisticReadLockTimeout: got write lock");

			bgTask = new FutureTask<Boolean>( new Callable() {
				public Boolean call() {
					try {
						boolean timedOut = false;	// true (success) if LockTimeoutException occurred
						em2.getTransaction().begin();
                        log.info("testContendedPessimisticReadLockTimeout: (BG) about to read write-locked entity");
						// we should block on the following read
						Lock lock2 = em2.getReference( Lock.class, id );
						lock2.getName();		//  force entity to be read
                        log.info("testContendedPessimisticReadLockTimeout: (BG) read write-locked entity");
						Map<String,Object> props = new HashMap();
						// timeout is in milliseconds
						props.put("javax.persistence.lock.timeout", new Integer(1000));
						try {
							em2.lock( lock2, LockModeType.PESSIMISTIC_READ, props);
						}
						catch( LockTimeoutException e) {
							// success
                            log.info("testContendedPessimisticReadLockTimeout: (BG) got expected timeout exception");
							 timedOut = true;
						}
						catch ( Throwable e) {
                            log.info("Expected LockTimeoutException but got unexpected exception", e);
						}
						em2.getTransaction().commit();
						return new Boolean(timedOut);
					}
					finally {
						latch.countDown();	// signal that we finished
					}
				}
			} );
			t = new Thread(bgTask);
			t.setDaemon( true );
			t.setName("Lock timeout Test (bg)");
			t.start();
			boolean latchSet = latch.await( 10, TimeUnit.SECONDS );  // should return quickly on success
			assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
			assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
			em.getTransaction().commit();
		}
		finally {
			if ( em.getTransaction().isActive() ) {
				em.getTransaction().rollback();
			}
			if ( t != null) {	  // wait for background thread to finish before deleting entity
				t.join();
			}
			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.remove( lock );
			em.getTransaction().commit();
			em.close();
			em2.close();
		}
	}

	@Test
	public void testContendedPessimisticWriteLockTimeout() throws Exception {

		EntityManager em = getOrCreateEntityManager();
		final EntityManager em2 = createIsolatedEntityManager();
		// TODO:  replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticLockTimeout)
		if ( ! (getDialect() instanceof Oracle10gDialect)) {
            log.info("skipping testContendedPessimisticWriteLockTimeout");
			return;
		}
		Lock lock = new Lock();
		Thread t = null;
		FutureTask<Boolean> bgTask = null;
		final CountDownLatch latch = new CountDownLatch(1);
		try {
			lock.setName( "testContendedPessimisticWriteLockTimeout" );

			em.getTransaction().begin();
			em.persist( lock );
			em.getTransaction().commit();
			em.clear();

			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
			final Integer id = lock.getId();
			lock.getName();		// force entity to be read
            log.info("testContendedPessimisticWriteLockTimeout: got write lock");

			bgTask = new FutureTask<Boolean>( new Callable() {
				public Boolean call() {
					try {
						boolean timedOut = false;	// true (success) if LockTimeoutException occurred
						em2.getTransaction().begin();
                        log.info("testContendedPessimisticWriteLockTimeout: (BG) about to read write-locked entity");
						// we should block on the following read
						Lock lock2 = em2.getReference( Lock.class, id );
						lock2.getName();		//  force entity to be read
                        log.info("testContendedPessimisticWriteLockTimeout: (BG) read write-locked entity");
						Map<String,Object> props = new HashMap();
						// timeout is in milliseconds
						props.put("javax.persistence.lock.timeout", new Integer(1000));
						try {
							em2.lock( lock2, LockModeType.PESSIMISTIC_WRITE, props);
						}
						catch( LockTimeoutException e) {
							// success
                            log.info("testContendedPessimisticWriteLockTimeout: (BG) got expected timeout exception");
							 timedOut = true;
						}
						catch ( Throwable e) {
                            log.info("Expected LockTimeoutException but got unexpected exception", e);
						}
						em2.getTransaction().commit();
						return new Boolean(timedOut);
					}
					finally {
						latch.countDown();	// signal that we finished
					}
				}
			} );
			t = new Thread(bgTask);
			t.setDaemon( true );
			t.setName("Lock timeout Test (bg)");
			t.start();
			boolean latchSet = latch.await( 10, TimeUnit.SECONDS );  // should return quickly on success
			assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
			assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
			em.getTransaction().commit();
		}
		finally {
			if ( em.getTransaction().isActive() ) {
				em.getTransaction().rollback();
			}
			if ( t != null) {	  // wait for background thread to finish before deleting entity
				t.join();
			}
			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.remove( lock );
			em.getTransaction().commit();
			em.close();
			em2.close();
		}
	}

	@Test
	public void testContendedPessimisticWriteLockNoWait() throws Exception {

		EntityManager em = getOrCreateEntityManager();
		final EntityManager em2 = createIsolatedEntityManager();
		// TODO:  replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticLockTimeout)
		if ( ! (getDialect() instanceof Oracle10gDialect)) {
            log.info("skipping testContendedPessimisticWriteLockNoWait");
			return;
		}
		Lock lock = new Lock();
		Thread t = null;
		FutureTask<Boolean> bgTask = null;
		final CountDownLatch latch = new CountDownLatch(1);
		try {
			lock.setName( "testContendedPessimisticWriteLockNoWait" );

			em.getTransaction().begin();
			em.persist( lock );
			em.getTransaction().commit();
			em.clear();

			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
			final Integer id = lock.getId();
			lock.getName();		// force entity to be read
            log.info("testContendedPessimisticWriteLockNoWait: got write lock");

			bgTask = new FutureTask<Boolean>( new Callable() {
				public Boolean call() {
					try {
						boolean timedOut = false;	// true (success) if LockTimeoutException occurred
						em2.getTransaction().begin();
                        log.info("testContendedPessimisticWriteLockNoWait: (BG) about to read write-locked entity");
						// we should block on the following read
						Lock lock2 = em2.getReference( Lock.class, id );
						lock2.getName();		//  force entity to be read
                        log.info("testContendedPessimisticWriteLockNoWait: (BG) read write-locked entity");
						Map<String,Object> props = new HashMap();
						// timeout of zero means no wait (for lock)
						props.put("javax.persistence.lock.timeout", new Integer(0));
						try {
							em2.lock( lock2, LockModeType.PESSIMISTIC_WRITE, props);
						}
						catch( LockTimeoutException e) {
							// success
                            log.info("testContendedPessimisticWriteLockNoWait: (BG) got expected timeout exception");
							 timedOut = true;
						}
						catch ( Throwable e) {
                            log.info("Expected LockTimeoutException but got unexpected exception", e);
						}
						em2.getTransaction().commit();
						return new Boolean(timedOut);
					}
					finally {
						latch.countDown();	// signal that we finished
					}
				}
			} );
			t = new Thread(bgTask);
			t.setDaemon( true );
			t.setName("Lock timeout Test (bg)");
			t.start();
			boolean latchSet = latch.await( 10, TimeUnit.SECONDS );  // should return quickly on success
			assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
			assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
			em.getTransaction().commit();
		}
		finally {
			if ( em.getTransaction().isActive() ) {
				em.getTransaction().rollback();
			}
			if ( t != null) {	  // wait for background thread to finish before deleting entity
				t.join();
			}
			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.remove( lock );
			em.getTransaction().commit();
			em.close();
			em2.close();
		}
	}

	@Test
	public void testQueryTimeout() throws Exception {

		EntityManager em = getOrCreateEntityManager();
		final EntityManager em2 = createIsolatedEntityManager();
		// TODO:  replace dialect instanceof test with a Dialect.hasCapability
		if ( ! (getDialect() instanceof Oracle10gDialect)) {
            log.info("skipping testQueryTimeout");
			return;
		}
		Lock lock = new Lock();
		Thread t = null;
		FutureTask<Boolean> bgTask = null;
		final CountDownLatch latch = new CountDownLatch(1);
		try {
			lock.setName( "testQueryTimeout" );

			em.getTransaction().begin();
			em.persist( lock );
			em.getTransaction().commit();
			em.clear();

			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
			final Integer id = lock.getId();
			lock.getName();		// force entity to be read
            log.info("testQueryTimeout: got write lock");

			bgTask = new FutureTask<Boolean>( new Callable() {
				public Boolean call() {
					try {
						boolean timedOut = false;	// true (success) if LockTimeoutException occurred
						em2.getTransaction().begin();
                        log.info("testQueryTimeout: (BG) about to read write-locked entity");
						// we should block on the following read
						Lock lock2 = em2.getReference( Lock.class, id );
						lock2.getName();		//  force entity to be read
                        log.info("testQueryTimeout: (BG) read write-locked entity");
						try {
							// we should block on the following read
							Query query = em2.createQuery(
									  "select L from Lock_ L where L.id < 10000 ");
							query.setLockMode( LockModeType.PESSIMISTIC_READ );
							query.setHint( "javax.persistence.query.timeout", new Integer(500) ); // 1 sec timeout
							List<Lock> resultList = query.getResultList();
							String name = resultList.get(0).getName(); //  force entity to be read
                            log.info("testQueryTimeout: name read =" + name);
						}
						catch( QueryTimeoutException e) {
							// success
                            log.info("testQueryTimeout: (BG) got expected timeout exception");
							 timedOut = true;
						}
						catch ( Throwable e) {
                            log.info("testQueryTimeout: Expected LockTimeoutException but got unexpected exception", e);
						}
						em2.getTransaction().commit();
						return new Boolean( timedOut );
					}
					finally {
						latch.countDown();	// signal that we finished
					}
				}
			} );
			t = new Thread(bgTask);
			t.setDaemon( true );
			t.setName( "testQueryTimeout (bg)" );
			t.start();
			boolean latchSet = latch.await( 10, TimeUnit.SECONDS );  // should return quickly on success
			assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
			assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
			em.getTransaction().commit();
		}
		finally {
			if ( em.getTransaction().isActive() ) {
				em.getTransaction().rollback();
			}
			if ( t != null) {	  // wait for background thread to finish before deleting entity
				t.join();
			}
			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.remove( lock );
			em.getTransaction().commit();
			em.close();
			em2.close();
		}
	}

	@Test
	public void testQueryTimeoutEMProps() throws Exception {
		// TODO:  replace dialect instanceof test with a Dialect.hasCapability
		if ( ! (getDialect() instanceof Oracle10gDialect)) {
            log.info("skipping testQueryTimeout");
			return;
 		}
		EntityManager em = getOrCreateEntityManager();
		Map queryTimeoutProps = new HashMap();
		queryTimeoutProps.put("javax.persistence.query.timeout", new Integer(500) ); // 1 sec timeout (should round up)
		final EntityManager em2 = createIsolatedEntityManager(queryTimeoutProps);
		Lock lock = new Lock();
		Thread t = null;
		FutureTask<Boolean> bgTask = null;
		final CountDownLatch latch = new CountDownLatch(1);
		try {
			lock.setName( "testQueryTimeout" );

			em.getTransaction().begin();
			em.persist( lock );
			em.getTransaction().commit();
			em.clear();

			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
			final Integer id = lock.getId();
			lock.getName();		// force entity to be read
            log.info("testQueryTimeout: got write lock");

			bgTask = new FutureTask<Boolean>( new Callable() {
				public Boolean call() {
					try {
						boolean timedOut = false;	// true (success) if LockTimeoutException occurred
						em2.getTransaction().begin();
                        log.info("testQueryTimeout: (BG) about to read write-locked entity");
						// we should block on the following read
						Lock lock2 = em2.getReference( Lock.class, id );
						lock2.getName();		//  force entity to be read
                        log.info("testQueryTimeout: (BG) read write-locked entity");
						try {
							// we should block on the following read
							Query query = em2.createQuery(
									  "select L from Lock_ L where L.id < 10000 ");
							query.setLockMode( LockModeType.PESSIMISTIC_READ );
							List<Lock> resultList = query.getResultList();
							String name = resultList.get(0).getName(); //  force entity to be read
                            log.info("testQueryTimeout: name read =" + name);
						}
						catch( QueryTimeoutException e) {
							// success
                            log.info("testQueryTimeout: (BG) got expected timeout exception");
							 timedOut = true;
						}
						catch ( Throwable e) {
                            log.info("testQueryTimeout: Expected LockTimeoutException but got unexpected exception", e);
						}
						em2.getTransaction().commit();
						return new Boolean( timedOut );
					}
					finally {
						latch.countDown();	// signal that we finished
					}
				}
			} );
			t = new Thread(bgTask);
			t.setDaemon( true );
			t.setName( "testQueryTimeout (bg)" );
			t.start();
			boolean latchSet = latch.await( 10, TimeUnit.SECONDS );  // should return quickly on success
			assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
			assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
			em.getTransaction().commit();
		}
		finally {
			if ( em.getTransaction().isActive() ) {
				em.getTransaction().rollback();
			}
			if ( t != null) {	  // wait for background thread to finish before deleting entity
				t.join();
			}
			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.remove( lock );
			em.getTransaction().commit();
			em.close();
			em2.close();
		}
	}


	@Test
	public void testLockTimeoutEMProps() throws Exception {

		EntityManager em = getOrCreateEntityManager();
		Map TimeoutProps = new HashMap();
		TimeoutProps.put("javax.persistence.lock.timeout", new Integer(1000) ); // 1 second timeout
		final EntityManager em2 = createIsolatedEntityManager(TimeoutProps);
		// TODO:  replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticLockTimeout)
		if ( ! (getDialect() instanceof Oracle10gDialect)) {
            log.info("skipping testLockTimeoutEMProps");
			return;
		}
		Lock lock = new Lock();
		Thread t = null;
		FutureTask<Boolean> bgTask = null;
		final CountDownLatch latch = new CountDownLatch(1);
		try {
			lock.setName( "testLockTimeoutEMProps" );

			em.getTransaction().begin();
			em.persist( lock );
			em.getTransaction().commit();
			em.clear();

			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
			final Integer id = lock.getId();
			lock.getName();		// force entity to be read
            log.info("testLockTimeoutEMProps: got write lock");

			bgTask = new FutureTask<Boolean>( new Callable() {
				public Boolean call() {
					try {
						boolean timedOut = false;	// true (success) if LockTimeoutException occurred
						em2.getTransaction().begin();
                        log.info("testLockTimeoutEMProps: (BG) about to read write-locked entity");
						// we should block on the following read
						Lock lock2 = em2.getReference( Lock.class, id );
						lock2.getName();		//  force entity to be read
                        log.info("testLockTimeoutEMProps: (BG) read write-locked entity");
						// em2 already has javax.persistence.lock.timeout of 1 second applied
						try {
							em2.lock( lock2, LockModeType.PESSIMISTIC_WRITE);
						}
						catch( LockTimeoutException e) {
							// success
                            log.info("testLockTimeoutEMProps: (BG) got expected timeout exception");
							 timedOut = true;
						}
						catch ( Throwable e) {
                            log.info("Expected LockTimeoutException but got unexpected exception", e);
						}
						em2.getTransaction().commit();
						return new Boolean(timedOut);
					}
					finally {
						latch.countDown();	// signal that we finished
					}
				}
			} );
			t = new Thread(bgTask);
			t.setDaemon( true );
			t.setName("Lock timeout Test (bg)");
			t.start();
			boolean latchSet = latch.await( 10, TimeUnit.SECONDS );  // should return quickly on success
			assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
			assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
			em.getTransaction().commit();
		}
		finally {
			if ( em.getTransaction().isActive() ) {
				em.getTransaction().rollback();
			}
			if ( t != null) {	  // wait for background thread to finish before deleting entity
				t.join();
			}
			em.getTransaction().begin();
			lock = em.getReference( Lock.class, lock.getId() );
			em.remove( lock );
			em.getTransaction().commit();
			em.close();
			em2.close();
		}
	}

	@Override
	public Class[] getAnnotatedClasses() {
		return new Class[]{
				Lock.class,
				UnversionedLock.class
		};
	}
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate LockTest.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.