[hibernate-commits] Hibernate SVN: r17944 - in core/trunk: core/src/main/java/org/hibernate/action and 8 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Fri Nov 6 08:59:37 EST 2009


Author: smarlow at redhat.com
Date: 2009-11-06 08:59:37 -0500 (Fri, 06 Nov 2009)
New Revision: 17944

Added:
   core/trunk/core/src/main/java/org/hibernate/OptimisticLockException.java
   core/trunk/core/src/main/java/org/hibernate/PessimisticLockException.java
   core/trunk/core/src/main/java/org/hibernate/action/EntityIncrementVersionProcess.java
   core/trunk/core/src/main/java/org/hibernate/action/EntityVerifyVersionProcess.java
Modified:
   core/trunk/core/src/main/java/org/hibernate/LockMode.java
   core/trunk/core/src/main/java/org/hibernate/cfg/ResultSetMappingBinder.java
   core/trunk/core/src/main/java/org/hibernate/dialect/Dialect.java
   core/trunk/core/src/main/java/org/hibernate/engine/EntityEntry.java
   core/trunk/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java
   core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java
   core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLockEventListener.java
   core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryImpl.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java
Log:
HHH-4546 -  add JPA 2.0 locking

Modified: core/trunk/core/src/main/java/org/hibernate/LockMode.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/LockMode.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/core/src/main/java/org/hibernate/LockMode.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -87,6 +87,7 @@
 	/**
 	 * An upgrade lock. Objects loaded in this lock mode are
 	 * materialized using an SQL <tt>select ... for update</tt>.
+	 * @deprecated instead use PESSIMISTIC_WRITE
 	 */
 	public static final LockMode UPGRADE = new LockMode(10, "UPGRADE");
 	/**
@@ -107,9 +108,47 @@
 	/**
 	 * Similiar to {@link #UPGRADE} except that, for versioned entities,
 	 * it results in a forced version increment.
+	 * @deprecated instead use PESSIMISTIC_FORCE_INCREMENT
 	 */
 	public static final LockMode FORCE = new LockMode( 15, "FORCE" );
 
+	/**
+	 *  start of javax.persistence.LockModeType equivalent modes
+	 */
+
+	/**
+	 * Optimisticly assume that transaction will not experience contention for
+	 * entities.  The entity version will be verified near the transaction end.  
+	 */
+	public static final LockMode OPTIMISTIC = new LockMode(3,"OPTIMISTIC");
+
+	/**
+	 * Optimisticly assume that transaction will not experience contention for entities.
+	 * The entity version will be verified and incremented near the transaction end. 
+	 */
+	public static final LockMode OPTIMISTIC_FORCE_INCREMENT = new LockMode(7,"OPTIMISTIC_FORCE_INCREMENT");
+
+	/**
+	 * Implemented as PESSIMISTIC_WRITE.
+	 * TODO:  introduce separate support for PESSIMISTIC_READ
+	 */
+	public static final LockMode PESSIMISTIC_READ = new LockMode(12,"PESSIMISTIC_READ");
+
+	/**
+	 * Transaction will obtain a database lock immediately.
+	 * TODO:  add PESSIMISTIC_WRITE_NOWAIT
+	 */
+	public static final LockMode PESSIMISTIC_WRITE = new LockMode(13,"PESSIMISTIC_WRITE");
+
+	/**
+	 * Transaction will immediately increment the entity version.
+	 */
+	public static final LockMode PESSIMISTIC_FORCE_INCREMENT = new LockMode(17,"PESSIMISTIC_FORCE_INCREMENT");
+
+	/**
+	 *  end of javax.persistence.LockModeType modes
+	 */
+	
 	static {
 		INSTANCES.put( NONE.name, NONE );
 		INSTANCES.put( READ.name, READ );
@@ -117,6 +156,11 @@
 		INSTANCES.put( UPGRADE_NOWAIT.name, UPGRADE_NOWAIT );
 		INSTANCES.put( WRITE.name, WRITE );
 		INSTANCES.put( FORCE.name, FORCE );
+		INSTANCES.put( OPTIMISTIC.name, OPTIMISTIC);
+		INSTANCES.put( OPTIMISTIC_FORCE_INCREMENT.name, OPTIMISTIC_FORCE_INCREMENT);
+		INSTANCES.put( PESSIMISTIC_READ. name, PESSIMISTIC_READ);
+		INSTANCES.put( PESSIMISTIC_WRITE.name, PESSIMISTIC_WRITE);
+		INSTANCES.put( PESSIMISTIC_FORCE_INCREMENT.name, PESSIMISTIC_FORCE_INCREMENT);
 	}
 
 	private Object readResolve() {

Added: core/trunk/core/src/main/java/org/hibernate/OptimisticLockException.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/OptimisticLockException.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/OptimisticLockException.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -0,0 +1,51 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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;
+
+/**
+ *
+ * Throw when an optimistic locking conflict occurs.
+ *
+ * @author Scott Marlow
+ */
+public class OptimisticLockException extends HibernateException {
+
+	Object entity;
+
+	public OptimisticLockException(String s) {
+		super(s);
+	}
+
+	public OptimisticLockException(String s, Object entity) {
+		super(s);
+		this.entity = entity;
+	}
+
+	public Object getEntity() {
+		return entity;
+	}
+
+
+}
\ No newline at end of file

Added: core/trunk/core/src/main/java/org/hibernate/PessimisticLockException.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/PessimisticLockException.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/PessimisticLockException.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -0,0 +1,50 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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;
+
+/**
+ *
+ * Throw when an pessimistic locking conflict occurs.
+ *
+ * @author Scott Marlow
+ */
+public class PessimisticLockException extends HibernateException {
+
+	Object entity;
+
+	public PessimisticLockException(String s) {
+		super(s);
+	}
+
+	public PessimisticLockException(String s, Object entity) {
+		super(s);
+		this.entity = entity;
+	}
+
+	public Object getEntity() {
+		return entity;
+	}
+
+}
\ No newline at end of file

Added: core/trunk/core/src/main/java/org/hibernate/action/EntityIncrementVersionProcess.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/action/EntityIncrementVersionProcess.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/action/EntityIncrementVersionProcess.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -0,0 +1,58 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.action;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Verify/Increment the entity version
+ *
+ * @author Scott Marlow
+ */
+public class EntityIncrementVersionProcess implements BeforeTransactionCompletionProcess
+{
+	private final Object object;
+	private final EntityEntry entry;
+
+	public EntityIncrementVersionProcess(Object object, EntityEntry entry) {
+		this.object = object;
+		this.entry = entry;
+	}
+
+	/**
+	 * Perform whatever processing is encapsulated here before completion of the transaction.
+	 *
+	 * @param session The session on which the transaction is preparing to complete.
+	 */
+	public void doBeforeTransactionCompletion(SessionImplementor session) {
+		final EntityPersister persister = entry.getPersister();
+		Object nextVersion = persister.forceVersionIncrement(
+				entry.getId(), entry.getVersion(), session
+		);
+		entry.forceLocked( object, nextVersion );
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/action/EntityVerifyVersionProcess.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/action/EntityVerifyVersionProcess.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/action/EntityVerifyVersionProcess.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -0,0 +1,64 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.action;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.HibernateException;
+import org.hibernate.OptimisticLockException;
+
+/**
+ * Verify/Increment the entity version
+ *
+ * @author Scott Marlow
+ */
+public class EntityVerifyVersionProcess implements BeforeTransactionCompletionProcess
+{
+	private final Object object;
+	private final EntityEntry entry;
+
+	public EntityVerifyVersionProcess(Object object, EntityEntry entry) {
+		this.object = object;
+		this.entry = entry;
+	}
+
+	/**
+	 * Perform whatever processing is encapsulated here before completion of the transaction.
+	 *
+	 * @param session The session on which the transaction is preparing to complete.
+	 */
+	public void doBeforeTransactionCompletion(SessionImplementor session) {
+		final EntityPersister persister = entry.getPersister();
+
+		Object latestVersion = persister.getCurrentVersion(
+			entry.getId(), session
+		);
+	   if(!entry.getVersion().equals(latestVersion))
+			throw new OptimisticLockException(
+				"Newer version ("+ latestVersion+
+				") of entity ("+entry.getEntityName()+") found in database.  id=" +  entry.getId());
+	}
+}
\ No newline at end of file

Modified: core/trunk/core/src/main/java/org/hibernate/cfg/ResultSetMappingBinder.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/cfg/ResultSetMappingBinder.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/core/src/main/java/org/hibernate/cfg/ResultSetMappingBinder.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -382,6 +382,21 @@
 		else if ( "force".equals( lockMode ) ) {
 			return LockMode.FORCE;
 		}
+		else if ( "optimistic".equals( lockMode ) ) {
+			return LockMode.OPTIMISTIC;
+		}
+		else if ( "optimistic_force_increment".equals( lockMode ) ) {
+			return LockMode.OPTIMISTIC_FORCE_INCREMENT;
+		}
+		else if ( "pessimistic_read".equals( lockMode ) ) {
+			return LockMode.PESSIMISTIC_READ;
+		}
+		else if ( "pessimistic_write".equals( lockMode ) ) {
+			return LockMode.PESSIMISTIC_WRITE;
+		}
+		else if ( "pessimistic_force_increment".equals( lockMode ) ) {
+			return LockMode.PESSIMISTIC_FORCE_INCREMENT;
+		}
 		else {
 			throw new MappingException( "unknown lockmode" );
 		}

Modified: core/trunk/core/src/main/java/org/hibernate/dialect/Dialect.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/Dialect.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/Dialect.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -962,13 +962,13 @@
 	 * @return The appropriate for update fragment.
 	 */
 	public String getForUpdateString(LockMode lockMode) {
-		if ( lockMode==LockMode.UPGRADE ) {
+		if ( lockMode==LockMode.UPGRADE || lockMode==LockMode.PESSIMISTIC_READ || lockMode==LockMode.PESSIMISTIC_WRITE) {
 			return getForUpdateString();
 		}
 		else if ( lockMode==LockMode.UPGRADE_NOWAIT ) {
 			return getForUpdateNowaitString();
 		}
-		else if ( lockMode==LockMode.FORCE ) {
+		else if ( lockMode==LockMode.FORCE || lockMode==LockMode.PESSIMISTIC_FORCE_INCREMENT) {
 			return getForUpdateNowaitString();
 		}
 		else {

Modified: core/trunk/core/src/main/java/org/hibernate/engine/EntityEntry.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/EntityEntry.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/core/src/main/java/org/hibernate/engine/EntityEntry.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -252,7 +252,7 @@
 	public void forceLocked(Object entity, Object nextVersion) {
 		version = nextVersion;
 		loadedState[ persister.getVersionProperty() ] = version;
-		setLockMode( LockMode.FORCE );
+		setLockMode( LockMode.FORCE );  // TODO:  use LockMode.PESSIMISTIC_FORCE_INCREMENT
 		persister.setPropertyValue(
 				entity,
 		        getPersister().getVersionProperty(),

Modified: core/trunk/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -29,11 +29,14 @@
 
 import org.hibernate.LockMode;
 import org.hibernate.ObjectDeletedException;
+import org.hibernate.OptimisticLockException;
+import org.hibernate.event.EventSource;
+import org.hibernate.action.EntityIncrementVersionProcess;
+import org.hibernate.action.EntityVerifyVersionProcess;
 import org.hibernate.cache.CacheKey;
 import org.hibernate.cache.access.SoftLock;
 import org.hibernate.engine.EntityEntry;
 import org.hibernate.engine.Status;
-import org.hibernate.engine.SessionImplementor;
 import org.hibernate.persister.entity.EntityPersister;
 import org.hibernate.pretty.MessageHelper;
 
@@ -55,7 +58,7 @@
 	 * @param requestedLockMode The lock mode being requested for locking.
 	 * @param source The session which is the source of the event being processed.
 	 */
-	protected void upgradeLock(Object object, EntityEntry entry, LockMode requestedLockMode, SessionImplementor source) {
+	protected void upgradeLock(Object object, EntityEntry entry, LockMode requestedLockMode, EventSource source) {
 
 		if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) {
 			// The user requested a "greater" (i.e. more restrictive) form of
@@ -97,13 +100,27 @@
 			}
 			
 			try {
-				if ( persister.isVersioned() && requestedLockMode == LockMode.FORCE ) {
+				if ( persister.isVersioned() && (requestedLockMode == LockMode.FORCE || requestedLockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT )  ) {
 					// todo : should we check the current isolation mode explicitly?
 					Object nextVersion = persister.forceVersionIncrement(
 							entry.getId(), entry.getVersion(), source
 					);
 					entry.forceLocked( object, nextVersion );
 				}
+				else if ( requestedLockMode == LockMode.OPTIMISTIC_FORCE_INCREMENT  ) {
+					if(!persister.isVersioned()) {
+						throw new OptimisticLockException("force: Version column is not mapped for " + entry.getPersister().getEntityName(), object);
+					}
+					EntityIncrementVersionProcess incrementVersion = new EntityIncrementVersionProcess(object, entry);
+					source.getActionQueue().registerProcess(incrementVersion);
+				}
+				else if ( requestedLockMode == LockMode.OPTIMISTIC  ) {
+					if(!persister.isVersioned()) {
+						throw new OptimisticLockException("Version column is not mapped for " + entry.getPersister().getEntityName(), object);					
+					}
+					EntityVerifyVersionProcess verifyVersion = new EntityVerifyVersionProcess(object, entry);
+					source.getActionQueue().registerProcess(verifyVersion);
+				}
 				else {
 					persister.lock( entry.getId(), entry.getVersion(), object, requestedLockMode, source );
 				}

Modified: core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -485,7 +485,7 @@
 					return INCONSISTENT_RTN_CLASS_MARKER;
 				}
 			}
-			upgradeLock( old, oldEntry, event.getLockMode(), session );
+			upgradeLock( old, oldEntry, event.getLockMode(), event.getSession() );
 		}
 
 		return old;

Modified: core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLockEventListener.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLockEventListener.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLockEventListener.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -80,11 +80,11 @@
 			}
 
 			entry = reassociate(event, entity, id, persister);
-			
+			// TODO:  make cascadeOnLock optional based on SCOPE
 			cascadeOnLock(event, persister, entity);
 		}
 
-		upgradeLock( entity, entry, event.getLockMode(), source );
+		upgradeLock( entity, entry, event.getLockMode(), event.getSession() );
 	}
 	
 	private void cascadeOnLock(LockEvent event, EntityPersister persister, Object entity) {

Modified: core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -1391,6 +1391,11 @@
 		lockers.put( LockMode.UPGRADE, generateLocker( LockMode.UPGRADE ) );
 		lockers.put( LockMode.UPGRADE_NOWAIT, generateLocker( LockMode.UPGRADE_NOWAIT ) );
 		lockers.put( LockMode.FORCE, generateLocker( LockMode.FORCE ) );
+		lockers.put( LockMode.PESSIMISTIC_READ, generateLocker( LockMode.PESSIMISTIC_READ ) );
+		lockers.put( LockMode.PESSIMISTIC_WRITE, generateLocker( LockMode.PESSIMISTIC_WRITE ) );
+		lockers.put( LockMode.PESSIMISTIC_FORCE_INCREMENT, generateLocker( LockMode.PESSIMISTIC_FORCE_INCREMENT ) );
+		lockers.put( LockMode.OPTIMISTIC, generateLocker( LockMode.OPTIMISTIC ) );
+		lockers.put( LockMode.OPTIMISTIC_FORCE_INCREMENT, generateLocker( LockMode.OPTIMISTIC_FORCE_INCREMENT ) );
 	}
 
 	protected LockingStrategy generateLocker(LockMode lockMode) {
@@ -3129,8 +3134,28 @@
 						readLoader :
 						createEntityLoader( LockMode.FORCE )
 			);
-
 		loaders.put(
+				LockMode.PESSIMISTIC_READ,
+				disableForUpdate ?
+						readLoader :
+						createEntityLoader( LockMode.PESSIMISTIC_READ )
+			);
+		loaders.put(
+				LockMode.PESSIMISTIC_WRITE,
+				disableForUpdate ?
+						readLoader :
+						createEntityLoader( LockMode.PESSIMISTIC_WRITE )
+			);
+		loaders.put(
+				LockMode.PESSIMISTIC_FORCE_INCREMENT,
+				disableForUpdate ?
+						readLoader :
+						createEntityLoader( LockMode.PESSIMISTIC_FORCE_INCREMENT )
+			);
+		loaders.put( LockMode.OPTIMISTIC, readLoader );
+		loaders.put( LockMode.OPTIMISTIC_FORCE_INCREMENT, readLoader );
+	
+		loaders.put(
 				"merge",
 				new CascadeEntityLoader( this, CascadingAction.MERGE, getFactory() )
 			);

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -38,6 +38,7 @@
 import javax.persistence.OptimisticLockException;
 import javax.persistence.PersistenceContextType;
 import javax.persistence.PersistenceException;
+import javax.persistence.PessimisticLockException;
 import javax.persistence.Query;
 import javax.persistence.TransactionRequiredException;
 import javax.persistence.TypedQuery;
@@ -53,22 +54,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.hibernate.AssertionFailure;
-import org.hibernate.FlushMode;
-import org.hibernate.HibernateException;
-import org.hibernate.LockMode;
-import org.hibernate.MappingException;
-import org.hibernate.ObjectDeletedException;
-import org.hibernate.ObjectNotFoundException;
-import org.hibernate.QueryException;
-import org.hibernate.SQLQuery;
-import org.hibernate.Session;
-import org.hibernate.StaleObjectStateException;
-import org.hibernate.StaleStateException;
-import org.hibernate.Transaction;
-import org.hibernate.TransientObjectException;
-import org.hibernate.TypeMismatchException;
-import org.hibernate.UnresolvableObjectException;
+import org.hibernate.*;
 import org.hibernate.cfg.Environment;
 import org.hibernate.ejb.transaction.JoinableCMTTransaction;
 import org.hibernate.ejb.util.ConfigurationHelper;
@@ -253,8 +239,21 @@
 
 	@SuppressWarnings("unchecked")
 	public <A> A find(Class<A> entityClass, Object primaryKey) {
+		LockModeType lmt = null;
+		return find( entityClass, primaryKey, lmt);
+	}
+
+	public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
+		return find(entityClass, primaryKey);
+	}
+
+	@SuppressWarnings("unchecked")
+	public <A> A find(Class<A> entityClass, Object  primaryKey, LockModeType lockModeType) {
 		try {
-			return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey );
+			if ( lockModeType != null )
+				return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey, getLockMode(lockModeType) );
+			else
+				return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey );
 		}
 		catch ( ObjectDeletedException e ) {
 			//the spec is silent about people doing remove() find() on the same PC
@@ -278,21 +277,10 @@
 		}
 	}
 
-	public <T> T find(Class<T> tClass, Object o, Map<String, Object> stringObjectMap) {
-		//FIXME
-		return null;  //To change body of implemented methods use File | Settings | File Templates.
+	public <A> A find(Class<A> entityClass, Object  primaryKey, LockModeType lockModeType, Map<String, Object> properties) {
+		return find(entityClass, primaryKey, lockModeType);
 	}
 
-	public <T> T find(Class<T> tClass, Object o, LockModeType lockModeType) {
-		//FIXME
-		return null;  //To change body of implemented methods use File | Settings | File Templates.
-	}
-
-	public <T> T find(Class<T> tClass, Object o, LockModeType lockModeType, Map<String, Object> stringObjectMap) {
-		//FIXME
-		return null;  //To change body of implemented methods use File | Settings | File Templates.
-	}
-
 	private void checkTransactionNeeded() {
 		if ( persistenceContextType == PersistenceContextType.TRANSACTION && !isTransactionInProgress() ) {
 			//no need to mark as rollback, no tx in progress
@@ -346,12 +334,25 @@
 	}
 
 	public void refresh(Object entity) {
+		LockModeType lmt = null;
+		refresh(entity, lmt);
+	}
+
+	public void refresh(Object entity, Map<String, Object> properties) {
+		LockModeType lmt = null;
+		refresh(entity, lmt);
+	}
+
+	public void refresh(Object entity, LockModeType lockModeType) {
 		checkTransactionNeeded();
 		try {
 			if ( !getSession().contains( entity ) ) {
 				throw new IllegalArgumentException( "Entity not managed" );
 			}
-			getSession().refresh( entity );
+			if(lockModeType != null)
+				getSession().refresh( entity, getLockMode(lockModeType) );
+			else
+				getSession().refresh( entity );
 		}
 		catch ( MappingException e ) {
 			throw new IllegalArgumentException( e.getMessage(), e );
@@ -361,21 +362,10 @@
 		}
 	}
 
-	public void refresh(Object o, Map<String, Object> stringObjectMap) {
-		//FIXME
-		//To change body of implemented methods use File | Settings | File Templates.
+	public void refresh(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
+		refresh(entity, lockModeType);
 	}
 
-	public void refresh(Object o, LockModeType lockModeType) {
-		//FIXME
-		//To change body of implemented methods use File | Settings | File Templates.
-	}
-
-	public void refresh(Object o, LockModeType lockModeType, Map<String, Object> stringObjectMap) {
-		//FIXME
-		//To change body of implemented methods use File | Settings | File Templates.
-	}
-
 	public boolean contains(Object entity) {
 		try {
 			if ( entity != null
@@ -393,9 +383,11 @@
 		}
 	}
 
-	public LockModeType getLockMode(Object o) {
-		//FIXME
-		return null;  //To change body of implemented methods use File | Settings | File Templates.
+	public LockModeType getLockMode(Object entity) {
+		if ( !contains( entity ) ) {
+			throw new IllegalArgumentException( "entity not in the persistence context" );
+		}
+		return this.getLockModeType(getSession().getCurrentLockMode(entity));
 	}
 
 	public void setProperty(String s, Object o) {
@@ -527,21 +519,57 @@
 			getSession().lock( entity, getLockMode( lockMode ) );
 		}
 		catch ( HibernateException he ) {
-			throwPersistenceException( he );
+			throw convert( he );
 		}
 	}
 
-	public void lock(Object o, LockModeType lockModeType, Map<String, Object> stringObjectMap) {
-		//FIXME
-		//To change body of implemented methods use File | Settings | File Templates.
+	public void lock(Object o, LockModeType lockModeType, Map<String, Object> properties) {
+		// todo:  support different properties passed in
+		lock(o,lockModeType);
 	}
 
+
+	private LockModeType getLockModeType(LockMode lockMode)
+	{
+		if ( lockMode == LockMode.NONE )
+			return LockModeType.NONE;
+		else if ( lockMode == LockMode.OPTIMISTIC || lockMode == LockMode.READ )
+			return LockModeType.OPTIMISTIC;
+		else if ( lockMode == LockMode.OPTIMISTIC_FORCE_INCREMENT || lockMode == LockMode.WRITE )
+			return LockModeType.OPTIMISTIC_FORCE_INCREMENT;
+		else if ( lockMode == LockMode.PESSIMISTIC_READ )
+			return LockModeType.PESSIMISTIC_READ;
+		else if ( lockMode == LockMode.PESSIMISTIC_WRITE )
+			return LockModeType.PESSIMISTIC_WRITE;
+		else if ( lockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT )
+			return LockModeType.PESSIMISTIC_FORCE_INCREMENT;
+		throw new AssertionFailure("unhandled lock mode " + lockMode );
+	}
+
+
 	private LockMode getLockMode(LockModeType lockMode) {
 		switch ( lockMode ) {
+
 			case READ:
-				return LockMode.UPGRADE; //assuming we are on read-commited and we need to prevent non repeteable read
+			case OPTIMISTIC:
+				return LockMode.OPTIMISTIC;
+
+			case OPTIMISTIC_FORCE_INCREMENT:
 			case WRITE:
-				return LockMode.FORCE;
+				return LockMode.OPTIMISTIC_FORCE_INCREMENT;
+
+			case PESSIMISTIC_READ:
+				return LockMode.PESSIMISTIC_READ;
+
+			case PESSIMISTIC_WRITE:
+				return LockMode.PESSIMISTIC_WRITE;
+
+			case PESSIMISTIC_FORCE_INCREMENT:
+				return LockMode.PESSIMISTIC_FORCE_INCREMENT;
+
+			case NONE:
+				return LockMode.NONE;
+
 			default:
 				throw new AssertionFailure( "Unknown LockModeType: " + lockMode );
 		}
@@ -772,6 +800,16 @@
 			handlePersistenceException( converted );
 			return converted;
 		}
+		else if ( e instanceof org.hibernate.OptimisticLockException ) {
+			PersistenceException converted = wrapLockException(e);
+			handlePersistenceException( converted );
+			return converted;
+		}
+		else if ( e instanceof org.hibernate.PessimisticLockException ) {
+			PersistenceException converted = wrapLockException(e); 
+			handlePersistenceException( converted );
+			return converted;
+		}
 		else if ( e instanceof ObjectNotFoundException ) {
 			EntityNotFoundException converted = new EntityNotFoundException( e.getMessage() );
 			handlePersistenceException( converted );
@@ -846,4 +884,21 @@
 		}
 		return pe;
 	}
+
+	public PersistenceException wrapLockException(HibernateException e) {
+		PersistenceException pe;
+		if ( e instanceof org.hibernate.OptimisticLockException ) {
+			 org.hibernate.OptimisticLockException ole = (org.hibernate.OptimisticLockException)e;
+			pe = new OptimisticLockException(ole.getMessage(), ole, ole.getEntity());
+		}
+		else if ( e instanceof org.hibernate.PessimisticLockException ) {
+			  org.hibernate.PessimisticLockException ple = (org.hibernate.PessimisticLockException)e;
+			pe = new PessimisticLockException(ple.getMessage(), ple, ple.getEntity());
+		}
+		else {
+			pe = new OptimisticLockException( e );
+		}
+		return pe;
+	}
+
 }

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -242,6 +242,17 @@
 		return QueryHints.getDefinedHints();
 	}
 
+	private javax.persistence.LockModeType jpaLockMode = javax.persistence.LockModeType.NONE;
+
+	public TypedQuery<X> setLockMode(javax.persistence.LockModeType lockModeType) {
+		this.jpaLockMode = lockModeType;
+		return this;
+	}
+
+	public javax.persistence.LockModeType getLockMode() {
+		return jpaLockMode;
+	}
+
 	private FlushModeType jpaFlushMode;
 
 	public TypedQuery<X> setFlushMode(FlushModeType jpaFlushMode) {

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryImpl.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryImpl.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -29,7 +29,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import javax.persistence.LockModeType;
+
 import javax.persistence.NoResultException;
 import javax.persistence.NonUniqueResultException;
 import javax.persistence.Parameter;
@@ -550,21 +550,6 @@
 	/**
 	 * {@inheritDoc}
 	 */
-	public TypedQuery<X> setLockMode(LockModeType lockModeType) {
-		// TODO : aye aye aye
-		throw new UnsupportedOperationException( "Not yet implemented" );
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public LockModeType getLockMode() {
-		return LockModeType.NONE;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
 	@SuppressWarnings({ "unchecked" })
 	public <T> T unwrap(Class<T> tClass) {
 		if ( org.hibernate.Query.class.isAssignableFrom( tClass ) ) {

Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -3,6 +3,7 @@
 
 import javax.persistence.EntityManager;
 import javax.persistence.LockModeType;
+import javax.persistence.OptimisticLockException;
 
 import org.hibernate.ejb.test.TestCase;
 
@@ -34,6 +35,29 @@
 		em.close();
 	}
 
+	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();
+	}
+
 	public void testLockWrite() throws Exception {
 		Lock lock = new Lock();
 		lock.setName( "second" );
@@ -70,7 +94,19 @@
 
 		em.getTransaction().begin();
 		lock = em.getReference( UnversionedLock.class, lock.getId() );
-		em.lock( lock, LockModeType.READ );
+		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();
@@ -80,6 +116,58 @@
 		em.close();
 	}
 
+	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();
+	}
+
+	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();
+	}
+	
 	public Class[] getAnnotatedClasses() {
 		return new Class[]{
 				Lock.class,

Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java	2009-11-06 13:20:10 UTC (rev 17943)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java	2009-11-06 13:59:37 UTC (rev 17944)
@@ -51,7 +51,7 @@
 	 * must always prevent the phenomena P1 and P2. Applications that call lock(entity, LockModeType.READ)
 	 * on non-versioned objects will not be portable.
 	 * <p/>
-	 * Odd as it may sound, EJB3 LockModeType.READ actually maps to the Hibernate LockMode.UPGRADE
+	 * EJB3 LockModeType.READ actually maps to the Hibernate LockMode.OPTIMISTIC
 	 */
 	public void testLockModeTypeRead() {
 		if ( !readCommittedIsolationMaintained( "ejb3 lock tests" ) ) {



More information about the hibernate-commits mailing list