Author: smarlow(a)redhat.com
Date: 2009-11-20 09:51:13 -0500 (Fri, 20 Nov 2009)
New Revision: 18016
Added:
core/trunk/core/src/main/java/org/hibernate/LockRequest.java
Modified:
core/trunk/core/src/main/java/org/hibernate/Session.java
core/trunk/core/src/main/java/org/hibernate/engine/CascadingAction.java
core/trunk/core/src/main/java/org/hibernate/event/LoadEvent.java
core/trunk/core/src/main/java/org/hibernate/event/LockEvent.java
core/trunk/core/src/main/java/org/hibernate/event/RefreshEvent.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/event/def/DefaultRefreshEventListener.java
core/trunk/core/src/main/java/org/hibernate/impl/SessionImpl.java
core/trunk/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java
core/trunk/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java
core/trunk/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java
core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java
core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java
core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
core/trunk/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
core/trunk/core/src/main/java/org/hibernate/util/ArrayHelper.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
core/trunk/testsuite/src/test/java/org/hibernate/test/legacy/CustomPersister.java
Log:
HHH-4546 add JPA 2.0 locking. Still need more LockRequest support in
AbstractEntityPersister.getAppropriateLoader(), may need to refactor.
Added: core/trunk/core/src/main/java/org/hibernate/LockRequest.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/LockRequest.java
(rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/LockRequest.java 2009-11-20 14:51:13 UTC
(rev 18016)
@@ -0,0 +1,115 @@
+/*
+ * 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;
+
+/**
+ * Contains locking details (LockMode, Timeout and Scope).
+ *
+ * @author Scott Marlow
+ */
+public class LockRequest
+{
+
+ public static final int NO_WAIT = 0;
+ public static final int WAIT_FOREVER = -1;
+
+ private LockMode lockMode = LockMode.NONE;
+
+ private int timeout = WAIT_FOREVER; // timeout in milliseconds, 0 = no wait, -1 = wait
indefinitely
+
+ private boolean scope=false;// if true, cascade (pessimistic only) lock to collections
and relationships
+ // owned by the entity.
+
+ public LockRequest() {
+
+ }
+
+ public LockRequest( LockMode lockMode, int timeout, boolean scope ) {
+ this.lockMode = lockMode;
+ this.timeout = timeout;
+ this.scope = scope;
+ }
+
+ /**
+ * Get the lock mode.
+ * @return the lock mode.
+ */
+ public LockMode getLockMode() {
+ return lockMode;
+ }
+
+ /**
+ * Specify the LockMode to be used. The default is LockMode.none.
+ *
+ * @param lockMode
+ * @return this LockRequest instance for operation chaining.
+ */
+ public LockRequest setLockMode(LockMode lockMode) {
+ this.lockMode = lockMode;
+ return this;
+ }
+
+ /**
+ * Get the timeout setting.
+ *
+ * @return timeout in milliseconds, -1 for indefinite wait and 0 for no wait.
+ */
+ public int getTimeOut() {
+ return timeout;
+ }
+
+ /**
+ * Specify the pessimistic lock timeout (check if your dialect supports this option).
+ * The default pessimistic lock behavior is to wait forever for the lock.
+ *
+ * @param timeout is time in milliseconds to wait for lock. -1 means wait forever and 0
means no wait.
+ * @return this LockRequest instance for operation chaining.
+ */
+ public LockRequest setTimeOut(int timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ /**
+ * Check if locking is cascaded to owned collections and relationships.
+ * @return true if locking will be extended to owned collections and relationships.
+ */
+ public boolean getScope() {
+ return scope;
+ }
+
+ /**
+ * Specify if LockMode should be cascaded to owned collections and relationships.
+ * The association must be mapped with <tt>cascade="lock" for scope=true
to work.
+ *
+ * @param scope
+ * @return
+ */
+ public LockRequest setScope(boolean scope) {
+ this.scope = scope;
+ return this;
+ }
+
+}
Modified: core/trunk/core/src/main/java/org/hibernate/Session.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/Session.java 2009-11-20 14:01:40 UTC (rev
18015)
+++ core/trunk/core/src/main/java/org/hibernate/Session.java 2009-11-20 14:51:13 UTC (rev
18016)
@@ -270,6 +270,7 @@
* @param lockMode the lock level
* @return the persistent instance or proxy
* @throws HibernateException
+ * @deprecated LockMode parameter should be replaced with a LockRequest
*/
public Object load(Class theClass, Serializable id, LockMode lockMode) throws
HibernateException;
@@ -277,16 +278,41 @@
* Return the persistent instance of the given entity class with the given identifier,
* obtaining the specified lock mode, assuming the instance exists.
*
+ * @param theClass a persistent class
+ * @param id a valid identifier of an existing persistent instance of the class
+ * @param lockRequest contains the lock level
+ * @return the persistent instance or proxy
+ * @throws HibernateException
+ */
+ public Object load(Class theClass, Serializable id, LockRequest lockRequest) throws
HibernateException;
+
+ /**
+ * Return the persistent instance of the given entity class with the given identifier,
+ * obtaining the specified lock mode, assuming the instance exists.
+ *
* @param entityName a persistent class
* @param id a valid identifier of an existing persistent instance of the class
* @param lockMode the lock level
* @return the persistent instance or proxy
* @throws HibernateException
+ * @deprecated LockMode parameter should be replaced with a LockRequest
*/
public Object load(String entityName, Serializable id, LockMode lockMode) throws
HibernateException;
/**
* Return the persistent instance of the given entity class with the given identifier,
+ * obtaining the specified lock mode, assuming the instance exists.
+ *
+ * @param entityName a persistent class
+ * @param id a valid identifier of an existing persistent instance of the class
+ * @param lockRequest contains the lock level
+ * @return the persistent instance or proxy
+ * @throws HibernateException
+ */
+ public Object load(String entityName, Serializable id, LockRequest lockRequest) throws
HibernateException;
+
+ /**
+ * Return the persistent instance of the given entity class with the given identifier,
* assuming that the instance exists. This method might return a proxied instance that
* is initialized on-demand, when a non-identifier method is accessed.
* <br><br>
@@ -500,30 +526,69 @@
/**
* Obtain the specified lock level upon the given object. This may be used to
* perform a version check (<tt>LockMode.READ</tt>), to upgrade to a
pessimistic
- * lock (<tt>LockMode.UPGRADE</tt>), or to simply reassociate a transient
instance
+ * lock (<tt>LockMode.PESSIMISTIC_WRITE</tt>), or to simply reassociate a
transient instance
* with a session (<tt>LockMode.NONE</tt>). This operation cascades to
associated
* instances if the association is mapped with
<tt>cascade="lock"</tt>.
*
* @param object a persistent or transient instance
* @param lockMode the lock level
* @throws HibernateException
+ * @deprecated LockMode parameter should be replaced with a LockRequest
*/
public void lock(Object object, LockMode lockMode) throws HibernateException;
/**
* Obtain the specified lock level upon the given object. This may be used to
- * perform a version check (<tt>LockMode.READ</tt>), to upgrade to a
pessimistic
- * lock (<tt>LockMode.UPGRADE</tt>), or to simply reassociate a transient
instance
+ * perform a version check (<tt>LockMode.OPTIMISTIC</tt>), to upgrade to a
pessimistic
+ * lock (<tt>LockMode.PESSIMISTIC_WRITE</tt>), or to simply reassociate a
transient instance
* with a session (<tt>LockMode.NONE</tt>). This operation cascades to
associated
+ * instances if the association is mapped with <tt>cascade="lock" and
lockRequest.getScope() == true</tt>.
+ *
+ * @param object a persistent or transient instance
+ * @param lockRequest contains the lock level
+ * @throws HibernateException
+ */
+ public void lock(Object object, LockRequest lockRequest) throws HibernateException;
+
+ /**
+ * Obtain the specified lock level upon the given object. This may be used to
+ * perform a version check (<tt>LockMode.OPTIMISTIC</tt>), to upgrade to a
pessimistic
+ * lock (<tt>LockMode.PESSIMISTIC_WRITE</tt>), or to simply reassociate a
transient instance
+ * with a session (<tt>LockMode.NONE</tt>). This operation cascades to
associated
* instances if the association is mapped with
<tt>cascade="lock"</tt>.
*
* @param object a persistent or transient instance
* @param lockMode the lock level
* @throws HibernateException
+ * @deprecated LockMode parameter should be replaced with a LockRequest
*/
public void lock(String entityName, Object object, LockMode lockMode) throws
HibernateException;
/**
+ * Obtain the specified lock level upon the given object. This may be used to
+ * perform a version check (<tt>LockMode.OPTIMISTIC</tt>), to upgrade to a
pessimistic
+ * lock (<tt>LockMode.PESSIMISTIC_WRITE</tt>), or to simply reassociate a
transient instance
+ * with a session (<tt>LockMode.NONE</tt>). This operation cascades to
associated
+ * instances if the association is mapped with <tt>cascade="lock" and
lockRequest.getScope() == true.</tt>.
+ *
+ * @param object a persistent or transient instance
+ * @param lockRequest contains the lock level
+ * @throws HibernateException
+ */
+ public void lock(String entityName, Object object, LockRequest lockRequest) throws
HibernateException;
+
+ /**
+ * Build a lockRequest that specifies the LockMode, pessimistic lock timeout and lock
scope.
+ * timeout and scope is ignored for optimistic locking.
+ *
+ * Use: LockRequest lr =
session.buildLockRequest().setLockMode(LockMode.PESSIMISTIC_WRITE).setTimeOut(1000 * 60);
+ * session.lock(entity, lr);
+ *
+ * @throws HibernateException
+ */
+ LockRequest buildLockRequest();
+
+ /**
* Re-read the state of the given instance from the underlying database. It is
* inadvisable to use this to implement long-running sessions that span many
* business tasks. This method is, however, useful in certain special circumstances.
@@ -548,10 +613,23 @@
* @param object a persistent or detached instance
* @param lockMode the lock mode to use
* @throws HibernateException
+ * @deprecated LockMode parameter should be replaced with a LockRequest
*/
public void refresh(Object object, LockMode lockMode) throws HibernateException;
/**
+ * Re-read the state of the given instance from the underlying database, with
+ * the given <tt>LockMode</tt>. It is inadvisable to use this to implement
+ * long-running sessions that span many business tasks. This method is, however,
+ * useful in certain special circumstances.
+ *
+ * @param object a persistent or detached instance
+ * @param lockRequest contains the lock mode to use
+ * @throws HibernateException
+ */
+ public void refresh(Object object, LockRequest lockRequest) throws HibernateException;
+
+ /**
* Determine the current lock mode of the given object.
*
* @param object a persistent instance
@@ -688,10 +766,25 @@
* @param lockMode the lock mode
* @return a persistent instance or null
* @throws HibernateException
+ * @deprecated LockMode parameter should be replaced with a LockRequest
*/
public Object get(Class clazz, Serializable id, LockMode lockMode) throws
HibernateException;
/**
+ * Return the persistent instance of the given entity class with the given identifier,
+ * or null if there is no such persistent instance. (If the instance is already
associated
+ * with the session, return that instance. This method never returns an uninitialized
instance.)
+ * Obtain the specified lock mode if the instance exists.
+ *
+ * @param clazz a persistent class
+ * @param id an identifier
+ * @param lockRequest the lock mode
+ * @return a persistent instance or null
+ * @throws HibernateException
+ */
+ public Object get(Class clazz, Serializable id, LockRequest lockRequest) throws
HibernateException;
+
+ /**
* Return the persistent instance of the given named entity with the given identifier,
* or null if there is no such persistent instance. (If the instance is already
associated
* with the session, return that instance. This method never returns an uninitialized
instance.)
@@ -714,9 +807,24 @@
* @param lockMode the lock mode
* @return a persistent instance or null
* @throws HibernateException
+ * @deprecated LockMode parameter should be replaced with a LockRequest
*/
public Object get(String entityName, Serializable id, LockMode lockMode) throws
HibernateException;
+ /**
+ * Return the persistent instance of the given entity class with the given identifier,
+ * or null if there is no such persistent instance. (If the instance is already
associated
+ * with the session, return that instance. This method never returns an uninitialized
instance.)
+ * Obtain the specified lock mode if the instance exists.
+ *
+ * @param entityName the entity name
+ * @param id an identifier
+ * @param lockRequest contains the lock mode
+ * @return a persistent instance or null
+ * @throws HibernateException
+ */
+ public Object get(String entityName, Serializable id, LockRequest lockRequest) throws
HibernateException;
+
/**
* Return the entity name for a persistent entity
Modified: core/trunk/core/src/main/java/org/hibernate/engine/CascadingAction.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/CascadingAction.java 2009-11-20
14:01:40 UTC (rev 18015)
+++ core/trunk/core/src/main/java/org/hibernate/engine/CascadingAction.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -34,6 +34,7 @@
import org.hibernate.LockMode;
import org.hibernate.ReplicationMode;
import org.hibernate.TransientObjectException;
+import org.hibernate.LockRequest;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.collection.PersistentCollection;
@@ -165,7 +166,17 @@
if ( log.isTraceEnabled() ) {
log.trace( "cascading to lock: " + entityName );
}
- session.lock( entityName, child, LockMode.NONE/*(LockMode) anything*/ );
+ LockMode lockMode = LockMode.NONE;
+ LockRequest lr = new LockRequest();
+ if ( anything instanceof LockRequest ) {
+ LockRequest lockRequest = (LockRequest)anything;
+ lr.setTimeOut(lockRequest.getTimeOut());
+ lr.setScope( lockRequest.getScope());
+ if ( lockRequest.getScope() == true ) // cascade specified lockMode
+ lockMode = lockRequest.getLockMode();
+ }
+ lr.setLockMode(lockMode);
+ session.lock( entityName, child, lr);
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType
collectionType, Object collection) {
// lock doesn't cascade to uninitialized collections
Modified: core/trunk/core/src/main/java/org/hibernate/event/LoadEvent.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/LoadEvent.java 2009-11-20 14:01:40
UTC (rev 18015)
+++ core/trunk/core/src/main/java/org/hibernate/event/LoadEvent.java 2009-11-20 14:51:13
UTC (rev 18016)
@@ -27,6 +27,7 @@
import java.io.Serializable;
import org.hibernate.LockMode;
+import org.hibernate.LockRequest;
/**
* Defines an event class for the loading of an entity.
@@ -40,20 +41,24 @@
private Serializable entityId;
private String entityClassName;
private Object instanceToLoad;
- private LockMode lockMode;
+ private LockRequest lockRequest;
private boolean isAssociationFetch;
private Object result;
public LoadEvent(Serializable entityId, Object instanceToLoad, EventSource source) {
- this(entityId, null, instanceToLoad, null, false, source);
+ this(entityId, null, instanceToLoad, new LockRequest(), false, source);
}
public LoadEvent(Serializable entityId, String entityClassName, LockMode lockMode,
EventSource source) {
this(entityId, entityClassName, null, lockMode, false, source);
}
-
+
+ public LoadEvent(Serializable entityId, String entityClassName, LockRequest lockRequest,
EventSource source) {
+ this(entityId, entityClassName, null, lockRequest, false, source);
+ }
+
public LoadEvent(Serializable entityId, String entityClassName, boolean
isAssociationFetch, EventSource source) {
- this(entityId, entityClassName, null, null, isAssociationFetch, source);
+ this(entityId, entityClassName, null, new LockRequest(), isAssociationFetch, source);
}
public boolean isAssociationFetch() {
@@ -67,24 +72,34 @@
LockMode lockMode,
boolean isAssociationFetch,
EventSource source) {
+ this(entityId, entityClassName, instanceToLoad, new
LockRequest().setLockMode(lockMode), isAssociationFetch, source );
+ }
+ private LoadEvent(
+ Serializable entityId,
+ String entityClassName,
+ Object instanceToLoad,
+ LockRequest lockRequest,
+ boolean isAssociationFetch,
+ EventSource source) {
+
super(source);
if ( entityId == null ) {
throw new IllegalArgumentException("id to load is required for loading");
}
- if ( lockMode == LockMode.WRITE ) {
+ if ( lockRequest.getLockMode() == LockMode.WRITE ) {
throw new IllegalArgumentException("Invalid lock mode for loading");
}
- else if ( lockMode == null ) {
- lockMode = DEFAULT_LOCK_MODE;
+ else if ( lockRequest.getLockMode() == null ) {
+ lockRequest.setLockMode(DEFAULT_LOCK_MODE);
}
this.entityId = entityId;
this.entityClassName = entityClassName;
this.instanceToLoad = instanceToLoad;
- this.lockMode = lockMode;
+ this.lockRequest = lockRequest;
this.isAssociationFetch = isAssociationFetch;
}
@@ -112,14 +127,34 @@
this.instanceToLoad = instanceToLoad;
}
+ public LockRequest getLockRequest() {
+ return lockRequest;
+ }
+
public LockMode getLockMode() {
- return lockMode;
+ return lockRequest.getLockMode();
}
public void setLockMode(LockMode lockMode) {
- this.lockMode = lockMode;
+ this.lockRequest.setLockMode(lockMode);
}
+ public void setLockTimeout(int timeout) {
+ this.lockRequest.setTimeOut(timeout);
+ }
+
+ public int getLockTimeout() {
+ return this.lockRequest.getTimeOut();
+ }
+
+ public void setLockScope(boolean cascade) {
+ this.lockRequest.setScope(cascade);
+ }
+
+ public boolean getLockScope() {
+ return this.lockRequest.getScope();
+ }
+
public Object getResult() {
return result;
}
Modified: core/trunk/core/src/main/java/org/hibernate/event/LockEvent.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/LockEvent.java 2009-11-20 14:01:40
UTC (rev 18015)
+++ core/trunk/core/src/main/java/org/hibernate/event/LockEvent.java 2009-11-20 14:51:13
UTC (rev 18016)
@@ -25,6 +25,7 @@
package org.hibernate.event;
import org.hibernate.LockMode;
+import org.hibernate.LockRequest;
/**
* Defines an event class for the locking of an entity.
@@ -34,7 +35,7 @@
public class LockEvent extends AbstractEvent {
private Object object;
- private LockMode lockMode;
+ private LockRequest lockRequest;
private String entityName;
public LockEvent(String entityName, Object original, LockMode lockMode, EventSource
source) {
@@ -42,12 +43,23 @@
this.entityName = entityName;
}
+ public LockEvent(String entityName, Object original, LockRequest lockRequest,
EventSource source) {
+ this(original, lockRequest, source);
+ this.entityName = entityName;
+ }
+
public LockEvent(Object object, LockMode lockMode, EventSource source) {
super(source);
this.object = object;
- this.lockMode = lockMode;
+ this.lockRequest = new LockRequest().setLockMode(lockMode);
}
+ public LockEvent(Object object, LockRequest lockRequest, EventSource source) {
+ super(source);
+ this.object = object;
+ this.lockRequest = lockRequest;
+ }
+
public Object getObject() {
return object;
}
@@ -56,14 +68,34 @@
this.object = object;
}
+ public LockRequest getLockRequest() {
+ return lockRequest;
+ }
+
public LockMode getLockMode() {
- return lockMode;
+ return lockRequest.getLockMode();
}
public void setLockMode(LockMode lockMode) {
- this.lockMode = lockMode;
+ this.lockRequest.setLockMode(lockMode);
}
+ public void setLockTimeout(int timeout) {
+ this.lockRequest.setTimeOut(timeout);
+ }
+
+ public int getLockTimeout() {
+ return this.lockRequest.getTimeOut();
+ }
+
+ public void setLockScope(boolean cascade) {
+ this.lockRequest.setScope(cascade);
+ }
+
+ public boolean getLockScope() {
+ return this.lockRequest.getScope();
+ }
+
public String getEntityName() {
return entityName;
}
Modified: core/trunk/core/src/main/java/org/hibernate/event/RefreshEvent.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/RefreshEvent.java 2009-11-20
14:01:40 UTC (rev 18015)
+++ core/trunk/core/src/main/java/org/hibernate/event/RefreshEvent.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -25,6 +25,7 @@
package org.hibernate.event;
import org.hibernate.LockMode;
+import org.hibernate.LockRequest;
/**
* Defines an event class for the refreshing of an object.
@@ -34,7 +35,7 @@
public class RefreshEvent extends AbstractEvent {
private Object object;
- private LockMode lockMode = LockMode.READ;
+ private LockRequest lockRequest = new LockRequest().setLockMode(LockMode.READ);
public RefreshEvent(Object object, EventSource source) {
super(source);
@@ -49,14 +50,34 @@
if (lockMode == null) {
throw new IllegalArgumentException("Attempt to generate refresh event with null
lock mode");
}
- this.lockMode = lockMode;
+ this.lockRequest.setLockMode(lockMode);
}
+ public RefreshEvent(Object object, LockRequest lockRequest, EventSource source) {
+ this(object, source);
+ if (lockRequest == null) {
+ throw new IllegalArgumentException("Attempt to generate refresh event with null
lock request");
+ }
+ this.lockRequest = lockRequest;
+ }
+
public Object getObject() {
return object;
}
+ public LockRequest getLockRequest() {
+ return lockRequest;
+ }
+
public LockMode getLockMode() {
- return lockMode;
+ return lockRequest.getLockMode();
}
+
+ public int getLockTimeout() {
+ return this.lockRequest.getTimeOut();
+ }
+
+ public boolean getLockScope() {
+ return this.lockRequest.getScope();
+ }
}
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-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -30,6 +30,7 @@
import org.hibernate.LockMode;
import org.hibernate.ObjectDeletedException;
import org.hibernate.OptimisticLockException;
+import org.hibernate.LockRequest;
import org.hibernate.event.EventSource;
import org.hibernate.action.EntityIncrementVersionProcess;
import org.hibernate.action.EntityVerifyVersionProcess;
@@ -55,11 +56,12 @@
*
* @param object The entity for which to upgrade the lock.
* @param entry The entity's EntityEntry instance.
- * @param requestedLockMode The lock mode being requested for locking.
+ * @param lockRequest contains the requested lock mode.
* @param source The session which is the source of the event being processed.
*/
- protected void upgradeLock(Object object, EntityEntry entry, LockMode requestedLockMode,
EventSource source) {
+ protected void upgradeLock(Object object, EntityEntry entry, LockRequest lockRequest,
EventSource source) {
+ LockMode requestedLockMode = lockRequest.getLockMode();
if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) {
// The user requested a "greater" (i.e. more restrictive) form of
// pessimistic lock
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-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -485,7 +485,7 @@
return INCONSISTENT_RTN_CLASS_MARKER;
}
}
- upgradeLock( old, oldEntry, event.getLockMode(), event.getSession() );
+ upgradeLock( old, oldEntry, event.getLockRequest(), 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-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLockEventListener.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -80,11 +80,10 @@
}
entry = reassociate(event, entity, id, persister);
- // TODO: make cascadeOnLock optional based on SCOPE
cascadeOnLock(event, persister, entity);
}
- upgradeLock( entity, entry, event.getLockMode(), event.getSession() );
+ upgradeLock( entity, entry, event.getLockRequest(), event.getSession() );
}
private void cascadeOnLock(LockEvent event, EntityPersister persister, Object entity) {
@@ -92,7 +91,7 @@
source.getPersistenceContext().incrementCascadeLevel();
try {
new Cascade(CascadingAction.LOCK, Cascade.AFTER_LOCK, source)
- .cascade( persister, entity, event.getLockMode() );
+ .cascade( persister, entity, event.getLockRequest() );
}
finally {
source.getPersistenceContext().decrementCascadeLevel();
Modified:
core/trunk/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java
===================================================================
---
core/trunk/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java 2009-11-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -142,7 +142,7 @@
String previousFetchProfile = source.getFetchProfile();
source.setFetchProfile("refresh");
- Object result = persister.load( id, object, event.getLockMode(), source );
+ Object result = persister.load( id, object, event.getLockRequest(), source );
source.setFetchProfile(previousFetchProfile);
UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() );
Modified: core/trunk/core/src/main/java/org/hibernate/impl/SessionImpl.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/impl/SessionImpl.java 2009-11-20 14:01:40
UTC (rev 18015)
+++ core/trunk/core/src/main/java/org/hibernate/impl/SessionImpl.java 2009-11-20 14:51:13
UTC (rev 18016)
@@ -69,6 +69,7 @@
import org.hibernate.UnresolvableObjectException;
import org.hibernate.UnknownProfileException;
import org.hibernate.EntityNameResolver;
+import org.hibernate.LockRequest;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.ActionQueue;
import org.hibernate.engine.CollectionEntry;
@@ -134,7 +135,6 @@
import org.hibernate.util.ArrayHelper;
import org.hibernate.util.CollectionHelper;
import org.hibernate.util.StringHelper;
-import org.hibernate.util.SerializationHelper;
/**
@@ -742,10 +742,23 @@
fireLock( new LockEvent(entityName, object, lockMode, this) );
}
+ public void lock(String entityName, Object object, LockRequest lockRequest) throws
HibernateException {
+ fireLock( new LockEvent(entityName, object, lockRequest, this) );
+ }
+
+ public LockRequest buildLockRequest() {
+ return new LockRequest();
+ }
+
public void lock(Object object, LockMode lockMode) throws HibernateException {
fireLock( new LockEvent(object, lockMode, this) );
}
+
+ public void lock(Object object, LockRequest lockRequest) throws HibernateException {
+ fireLock( new LockEvent(object, lockRequest, this) );
+ }
+
private void fireLock(LockEvent lockEvent) {
errorIfClosed();
checkTransactionSynchStatus();
@@ -1024,22 +1037,42 @@
return load( entityClass.getName(), id, lockMode );
}
+ public Object load(Class entityClass, Serializable id, LockRequest lockRequest) throws
HibernateException {
+ return load( entityClass.getName(), id, lockRequest );
+ }
+
public Object load(String entityName, Serializable id, LockMode lockMode) throws
HibernateException {
LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
fireLoad( event, LoadEventListener.LOAD );
return event.getResult();
}
+ public Object load(String entityName, Serializable id, LockRequest lockRequest) throws
HibernateException {
+ LoadEvent event = new LoadEvent(id, entityName, lockRequest, this);
+ fireLoad( event, LoadEventListener.LOAD );
+ return event.getResult();
+ }
+
public Object get(Class entityClass, Serializable id, LockMode lockMode) throws
HibernateException {
return get( entityClass.getName(), id, lockMode );
}
+ public Object get(Class entityClass, Serializable id, LockRequest lockRequest) throws
HibernateException {
+ return get( entityClass.getName(), id, lockRequest );
+ }
+
public Object get(String entityName, Serializable id, LockMode lockMode) throws
HibernateException {
LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
fireLoad(event, LoadEventListener.GET);
return event.getResult();
}
+ public Object get(String entityName, Serializable id, LockRequest lockRequest) throws
HibernateException {
+ LoadEvent event = new LoadEvent(id, entityName, lockRequest, this);
+ fireLoad(event, LoadEventListener.GET);
+ return event.getResult();
+ }
+
private void fireLoad(LoadEvent event, LoadType loadType) {
errorIfClosed();
checkTransactionSynchStatus();
@@ -1060,6 +1093,10 @@
fireRefresh( new RefreshEvent(object, lockMode, this) );
}
+ public void refresh(Object object, LockRequest lockRequest) throws HibernateException {
+ fireRefresh( new RefreshEvent(object, lockRequest, this) );
+ }
+
public void refresh(Object object, Map refreshedAlready) throws HibernateException {
fireRefresh( refreshedAlready, new RefreshEvent(object, this) );
}
Modified:
core/trunk/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java
===================================================================
---
core/trunk/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java 2009-11-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -31,6 +31,7 @@
import org.hibernate.FetchMode;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
+import org.hibernate.LockRequest;
import org.hibernate.engine.CascadeStyle;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
@@ -94,6 +95,29 @@
initStatementString( whereString, orderByString, lockMode);
}
+ protected final void initAll(
+ final String whereString,
+ final String orderByString,
+ final LockRequest lockRequest) throws MappingException {
+ walkEntityTree( persister, getAlias() );
+ List allAssociations = new ArrayList();
+ allAssociations.addAll(associations);
+ allAssociations.add(
+ new OuterJoinableAssociation(
+ persister.getEntityType(),
+ null,
+ null,
+ alias,
+ JoinFragment.LEFT_OUTER_JOIN,
+ null,
+ getFactory(),
+ CollectionHelper.EMPTY_MAP
+ )
+ );
+ initPersisters(allAssociations, lockRequest.getLockMode());
+ initStatementString( whereString, orderByString, lockRequest.getLockMode());
+ }
+
protected final void initProjection(
final String projectionString,
final String whereString,
Modified:
core/trunk/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java
===================================================================
---
core/trunk/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java 2009-11-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -28,8 +28,6 @@
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Modified:
core/trunk/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java
===================================================================
---
core/trunk/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java 2009-11-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -33,6 +33,7 @@
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
+import org.hibernate.LockRequest;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
@@ -128,4 +129,24 @@
}
}
+ public static UniqueEntityLoader createBatchingEntityLoader(
+ final OuterJoinLoadable persister,
+ final int maxBatchSize,
+ final LockRequest lockRequest,
+ final SessionFactoryImplementor factory,
+ final LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+
+ if ( maxBatchSize>1 ) {
+ int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
+ Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
+ for ( int i=0; i<batchSizesToCreate.length; i++ ) {
+ loadersToCreate[i] = new EntityLoader(persister, batchSizesToCreate[i], lockRequest,
factory, loadQueryInfluencers);
+ }
+ return new BatchingEntityLoader(persister, batchSizesToCreate, loadersToCreate);
+ }
+ else {
+ return new EntityLoader(persister, lockRequest, factory, loadQueryInfluencers);
+ }
+ }
+
}
Modified: core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java
===================================================================
---
core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java 2009-11-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -30,6 +30,7 @@
import org.hibernate.FetchMode;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
+import org.hibernate.LockRequest;
import org.hibernate.engine.CascadeStyle;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
@@ -47,7 +48,7 @@
*/
public class EntityJoinWalker extends AbstractEntityJoinWalker {
- private final LockMode lockMode;
+ private final LockRequest lockRequest = new LockRequest();
public EntityJoinWalker(
OuterJoinLoadable persister,
@@ -58,15 +59,35 @@
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( persister, factory, loadQueryInfluencers );
- this.lockMode = lockMode;
+ this.lockRequest.setLockMode(lockMode);
StringBuffer whereCondition = whereString( getAlias(), uniqueKey, batchSize )
//include the discriminator and class-level where, but not filters
.append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) );
- initAll( whereCondition.toString(), "", lockMode );
+ initAll( whereCondition.toString(), "", lockRequest );
}
+ public EntityJoinWalker(
+ OuterJoinLoadable persister,
+ String[] uniqueKey,
+ int batchSize,
+ LockRequest lockRequest,
+ SessionFactoryImplementor factory,
+ LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+ super( persister, factory, loadQueryInfluencers );
+
+ this.lockRequest.setLockMode(lockRequest.getLockMode());
+ this.lockRequest.setTimeOut(lockRequest.getTimeOut());
+ this.lockRequest.setScope(lockRequest.getScope());
+
+ StringBuffer whereCondition = whereString( getAlias(), uniqueKey, batchSize )
+ //include the discriminator and class-level where, but not filters
+ .append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) );
+
+ initAll( whereCondition.toString(), "", lockRequest);
+ }
+
protected int getJoinType(
OuterJoinLoadable persister,
String path,
@@ -81,7 +102,7 @@
// NOTE : we override this form here specifically to account for
// fetch profiles.
// TODO : how to best handle criteria queries?
- if ( lockMode.greaterThan( LockMode.READ ) ) {
+ if ( lockRequest.getLockMode().greaterThan( LockMode.READ ) ) {
return -1;
}
if ( isTooDeep( currentDepth )
Modified: core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java 2009-11-20
14:01:40 UTC (rev 18015)
+++ core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -24,12 +24,10 @@
*/
package org.hibernate.loader.entity;
-import java.util.Map;
-import java.util.Set;
-
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
+import org.hibernate.LockRequest;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
@@ -56,8 +54,16 @@
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
this( persister, 1, lockMode, factory, loadQueryInfluencers );
}
-
+
public EntityLoader(
+ OuterJoinLoadable persister,
+ LockRequest lockRequest,
+ SessionFactoryImplementor factory,
+ LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+ this( persister, 1, lockRequest, factory, loadQueryInfluencers );
+ }
+
+ public EntityLoader(
OuterJoinLoadable persister,
int batchSize,
LockMode lockMode,
@@ -75,6 +81,23 @@
}
public EntityLoader(
+ OuterJoinLoadable persister,
+ int batchSize,
+ LockRequest lockRequest,
+ SessionFactoryImplementor factory,
+ LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+ this(
+ persister,
+ persister.getIdentifierColumnNames(),
+ persister.getIdentifierType(),
+ batchSize,
+ lockRequest,
+ factory,
+ loadQueryInfluencers
+ );
+ }
+
+ public EntityLoader(
OuterJoinLoadable persister,
String[] uniqueKey,
Type uniqueKeyType,
@@ -102,6 +125,34 @@
}
+ public EntityLoader(
+ OuterJoinLoadable persister,
+ String[] uniqueKey,
+ Type uniqueKeyType,
+ int batchSize,
+ LockRequest lockRequest,
+ SessionFactoryImplementor factory,
+ LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+ super( persister, uniqueKeyType, factory, loadQueryInfluencers );
+
+ JoinWalker walker = new EntityJoinWalker(
+ persister,
+ uniqueKey,
+ batchSize,
+ lockRequest,
+ factory,
+ loadQueryInfluencers
+ );
+ initFromWalker( walker );
+
+ postInstantiate();
+
+ batchLoader = batchSize > 1;
+
+ log.debug( "Static select for entity " + entityName + ": " +
getSQLString() );
+
+ }
+
public Object loadByUniqueKey(
SessionImplementor session,
Object key) throws HibernateException {
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-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -46,6 +46,7 @@
import org.hibernate.QueryException;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
+import org.hibernate.LockRequest;
import org.hibernate.cache.CacheKey;
import org.hibernate.cache.access.EntityRegionAccessStrategy;
import org.hibernate.cache.entry.CacheEntry;
@@ -1412,8 +1413,17 @@
Object object,
LockMode lockMode,
SessionImplementor session) throws HibernateException {
- getLocker( lockMode ).lock( id, version, object, -1, session );
+ getLocker( lockMode ).lock( id, version, object, LockRequest.WAIT_FOREVER, session );
}
+
+ public void lock(
+ Serializable id,
+ Object version,
+ Object object,
+ LockRequest lockRequest,
+ SessionImplementor session) throws HibernateException {
+ getLocker( lockRequest.getLockMode() ).lock( id, version, object,
lockRequest.getTimeOut(), session );
+ }
public String getRootTableName() {
return getSubclassTableName( 0 );
@@ -1871,6 +1881,19 @@
);
}
+ protected UniqueEntityLoader createEntityLoader(
+ LockRequest lockRequest,
+ LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+ //TODO: disable batch loading if lockMode > READ?
+ return BatchingEntityLoader.createBatchingEntityLoader(
+ this,
+ batchSize,
+ lockRequest,
+ getFactory(),
+ loadQueryInfluencers
+ );
+ }
+
protected UniqueEntityLoader createEntityLoader(LockMode lockMode) throws
MappingException {
return createEntityLoader( lockMode, LoadQueryInfluencers.NONE );
}
@@ -3185,10 +3208,28 @@
);
}
- final UniqueEntityLoader loader = getAppropriateLoader( lockMode, session );
+ final UniqueEntityLoader loader = getAppropriateLoader( new
LockRequest().setLockMode(lockMode), session );
return loader.load( id, optionalObject, session );
}
+ /**
+ * Load an instance using either the <tt>forUpdateLoader</tt> or the outer
joining <tt>loader</tt>,
+ * depending upon the value of the <tt>lock</tt> parameter
+ */
+ public Object load(Serializable id, Object optionalObject, LockRequest lockRequest,
SessionImplementor session)
+ throws HibernateException {
+
+ if ( log.isTraceEnabled() ) {
+ log.trace(
+ "Fetching entity: " +
+ MessageHelper.infoString( this, id, getFactory() )
+ );
+ }
+
+ final UniqueEntityLoader loader = getAppropriateLoader( lockRequest, session );
+ return loader.load( id, optionalObject, session );
+ }
+
public void registerAffectingFetchProfile(String fetchProfileName) {
affectingFetchProfileNames.add( fetchProfileName );
}
@@ -3208,7 +3249,7 @@
&& filterHelper.isAffectedBy(
session.getLoadQueryInfluencers().getEnabledFilters() );
}
- private UniqueEntityLoader getAppropriateLoader(LockMode lockMode, SessionImplementor
session) {
+ private UniqueEntityLoader getAppropriateLoader(LockRequest lockRequest,
SessionImplementor session) {
if ( queryLoader != null ) {
// if the user specified a custom query loader we need to that
// regardless of any other consideration
@@ -3217,9 +3258,9 @@
else if ( isAffectedByEnabledFilters( session ) ) {
// because filters affect the rows returned (because they add
// restirctions) these need to be next in precendence
- return createEntityLoader( lockMode, session.getLoadQueryInfluencers() );
+ return createEntityLoader( lockRequest, session.getLoadQueryInfluencers() );
}
- else if ( session.getLoadQueryInfluencers().getInternalFetchProfile() != null
&& LockMode.UPGRADE.greaterThan( lockMode ) ) {
+ else if ( session.getLoadQueryInfluencers().getInternalFetchProfile() != null
&& LockMode.UPGRADE.greaterThan( lockRequest.getLockMode() ) ) {
// Next, we consider whether an 'internal' fetch profile has been set.
// This indicates a special fetch profile Hibernate needs applied
// (for its merge loading process e.g.).
@@ -3228,10 +3269,10 @@
else if ( isAffectedByEnabledFetchProfiles( session ) ) {
// If the session has associated influencers we need to adjust the
// SQL query used for loading based on those influencers
- return createEntityLoader( lockMode, session.getLoadQueryInfluencers() );
+ return createEntityLoader( lockRequest, session.getLoadQueryInfluencers() );
}
else {
- return ( UniqueEntityLoader ) loaders.get( lockMode );
+ return ( UniqueEntityLoader ) loaders.get( lockRequest.getLockMode() );
}
}
Modified:
core/trunk/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
===================================================================
---
core/trunk/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java 2009-11-20
14:01:40 UTC (rev 18015)
+++
core/trunk/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -31,6 +31,7 @@
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.EntityMode;
+import org.hibernate.LockRequest;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.cache.OptimisticCacheSource;
import org.hibernate.cache.access.EntityRegionAccessStrategy;
@@ -327,12 +328,24 @@
throws HibernateException;
/**
+ * Load an instance of the persistent class.
+ */
+ public Object load(Serializable id, Object optionalObject, LockRequest lockRequest,
SessionImplementor session)
+ throws HibernateException;
+
+ /**
* Do a version check (optional operation)
*/
public void lock(Serializable id, Object version, Object object, LockMode lockMode,
SessionImplementor session)
throws HibernateException;
/**
+ * Do a version check (optional operation)
+ */
+ public void lock(Serializable id, Object version, Object object, LockRequest
lockRequest, SessionImplementor session)
+ throws HibernateException;
+
+ /**
* Persist an instance
*/
public void insert(Serializable id, Object[] fields, Object object, SessionImplementor
session)
Modified: core/trunk/core/src/main/java/org/hibernate/util/ArrayHelper.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/util/ArrayHelper.java 2009-11-20 14:01:40
UTC (rev 18015)
+++ core/trunk/core/src/main/java/org/hibernate/util/ArrayHelper.java 2009-11-20 14:51:13
UTC (rev 18016)
@@ -32,6 +32,7 @@
import java.util.List;
import org.hibernate.LockMode;
+import org.hibernate.LockRequest;
import org.hibernate.type.Type;
public final class ArrayHelper {
@@ -83,6 +84,12 @@
return array;
}
+ public static LockMode[] fillArray(LockRequest lockRequest, int length) {
+ LockMode[] array = new LockMode[length];
+ Arrays.fill(array, lockRequest);
+ return array;
+ }
+
public static String[] toStringArray(Collection coll) {
return (String[]) coll.toArray( new String[coll.size()] );
}
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-20
14:01:40 UTC (rev 18015)
+++
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -29,6 +29,7 @@
import java.io.Serializable;
import java.util.Map;
import java.util.Set;
+import java.util.HashMap;
import javax.persistence.EntityNotFoundException;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
@@ -42,6 +43,7 @@
import javax.persistence.Query;
import javax.persistence.TransactionRequiredException;
import javax.persistence.TypedQuery;
+import javax.persistence.PessimisticLockScope;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.metamodel.Metamodel;
@@ -74,6 +76,8 @@
@SuppressWarnings("unchecked")
public abstract class AbstractEntityManagerImpl implements
HibernateEntityManagerImplementor, Serializable {
private static final Logger log = LoggerFactory.getLogger(
AbstractEntityManagerImpl.class );
+ private static final String PESSIMISTICLOCKSCOPE =
"javax.persistence.lock.scope";
+ private static final String PESSIMISTICLOCKTIMEOUT=
"javax.persistence.lock.timeout";
private EntityManagerFactoryImpl entityManagerFactory;
protected transient TransactionImpl tx = new TransactionImpl( this );
@@ -239,19 +243,22 @@
@SuppressWarnings("unchecked")
public <A> A find(Class<A> entityClass, Object primaryKey) {
- LockModeType lmt = null;
- return find( entityClass, primaryKey, lmt);
+ return find( entityClass, primaryKey, null, null);
}
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String,
Object> properties) {
- return find(entityClass, primaryKey);
+ return find(entityClass, primaryKey, null, null);
}
@SuppressWarnings("unchecked")
public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType
lockModeType) {
+ return find(entityClass, primaryKey, lockModeType, null);
+ }
+
+ public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType
lockModeType, Map<String, Object> properties) {
try {
if ( lockModeType != null )
- return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey,
getLockMode(lockModeType) );
+ return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey,
getLockRequest(lockModeType, properties) );
else
return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey );
}
@@ -277,10 +284,6 @@
}
}
- public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType
lockModeType, Map<String, Object> properties) {
- return find(entityClass, primaryKey, lockModeType);
- }
-
private void checkTransactionNeeded() {
if ( persistenceContextType == PersistenceContextType.TRANSACTION &&
!isTransactionInProgress() ) {
//no need to mark as rollback, no tx in progress
@@ -334,23 +337,25 @@
}
public void refresh(Object entity) {
- LockModeType lmt = null;
- refresh(entity, lmt);
+ refresh(entity, null, null);
}
public void refresh(Object entity, Map<String, Object> properties) {
- LockModeType lmt = null;
- refresh(entity, lmt);
+ refresh(entity, null, null);
}
public void refresh(Object entity, LockModeType lockModeType) {
+ refresh(entity, lockModeType, null);
+ }
+
+ public void refresh(Object entity, LockModeType lockModeType, Map<String, Object>
properties) {
checkTransactionNeeded();
try {
if ( !getSession().contains( entity ) ) {
throw new IllegalArgumentException( "Entity not managed" );
}
if(lockModeType != null)
- getSession().refresh( entity, getLockMode(lockModeType) );
+ getSession().refresh( entity, getLockRequest(lockModeType, properties) );
else
getSession().refresh( entity );
}
@@ -362,10 +367,6 @@
}
}
- public void refresh(Object entity, LockModeType lockModeType, Map<String, Object>
properties) {
- refresh(entity, lockModeType);
- }
-
public boolean contains(Object entity) {
try {
if ( entity != null
@@ -508,6 +509,10 @@
}
public void lock(Object entity, LockModeType lockMode) {
+ lock( entity, lockMode, null);
+ }
+
+ public void lock(Object entity, LockModeType lockModeType, Map<String, Object>
properties) {
try {
if ( !isTransactionInProgress() ) {
throw new TransactionRequiredException( "no transaction is in progress" );
@@ -516,21 +521,42 @@
if ( !contains( entity ) ) {
throw new IllegalArgumentException( "entity not in the persistence context"
);
}
- getSession().lock( entity, getLockMode( lockMode ) );
+ getSession().lock( entity, getLockRequest(lockModeType, properties) );
}
catch ( HibernateException he ) {
throw convert( he );
}
+
}
- public void lock(Object o, LockModeType lockModeType, Map<String, Object>
properties) {
- // todo: support different properties passed in
- lock(o,lockModeType);
+ private LockRequest getLockRequest(LockModeType lockModeType, Map<String, Object>
properties) {
+ LockRequest lockRequest = new LockRequest();
+ lockRequest.setLockMode(getLockMode(lockModeType));
+ if ( properties != null ) {
+ // lockRequest scope will default to false (PessimisticLockScope.NORMAL)
+ Object value = properties.get(PESSIMISTICLOCKSCOPE);
+ if ( value instanceof String && PessimisticLockScope.valueOf((String) value)
== PessimisticLockScope.EXTENDED) {
+ lockRequest.setScope(true);
+ }
+ // lockRequest timeout will default to LockRequest.FOREVER_WAIT
+ value = properties.get(PESSIMISTICLOCKTIMEOUT);
+ if ( value instanceof String ) {
+ int timeout = Integer.parseInt((String) value);
+ if ( timeout < 0 ) {
+ lockRequest.setTimeOut(LockRequest.WAIT_FOREVER);
+ }
+ else if( timeout == 0 ) {
+ lockRequest.setTimeOut(LockRequest.NO_WAIT);
+ }
+ else {
+ lockRequest.setTimeOut(timeout);
+ }
+ }
+ }
+ return lockRequest;
}
-
- private LockModeType getLockModeType(LockMode lockMode)
- {
+ private LockModeType getLockModeType(LockMode lockMode) {
if ( lockMode == LockMode.NONE )
return LockModeType.NONE;
else if ( lockMode == LockMode.OPTIMISTIC || lockMode == LockMode.READ )
Modified:
core/trunk/testsuite/src/test/java/org/hibernate/test/legacy/CustomPersister.java
===================================================================
---
core/trunk/testsuite/src/test/java/org/hibernate/test/legacy/CustomPersister.java 2009-11-20
14:01:40 UTC (rev 18015)
+++
core/trunk/testsuite/src/test/java/org/hibernate/test/legacy/CustomPersister.java 2009-11-20
14:51:13 UTC (rev 18016)
@@ -11,6 +11,7 @@
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
+import org.hibernate.LockRequest;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.cache.CacheConcurrencyStrategy;
import org.hibernate.cache.access.EntityRegionAccessStrategy;
@@ -280,6 +281,18 @@
}
/**
+ * @see EntityPersister#load(Serializable, Object, LockRequest, SessionImplementor)
+ */
+ public Object load(
+ Serializable id,
+ Object optionalObject,
+ LockRequest lockRequest,
+ SessionImplementor session
+ ) throws HibernateException {
+ return load(id, optionalObject, lockRequest.getLockMode(), session);
+ }
+
+ /**
* @see EntityPersister#load(Serializable, Object, LockMode, SessionImplementor)
*/
public Object load(
@@ -330,6 +343,20 @@
Serializable id,
Object version,
Object object,
+ LockRequest lockRequest,
+ SessionImplementor session
+ ) throws HibernateException {
+
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see EntityPersister#lock(Serializable, Object, Object, LockMode,
SessionImplementor)
+ */
+ public void lock(
+ Serializable id,
+ Object version,
+ Object object,
LockMode lockMode,
SessionImplementor session
) throws HibernateException {