/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate;
import java.io.
Serializable;
import java.util.
Collections;
import java.util.
HashMap;
import java.util.
Iterator;
import java.util.
LinkedHashMap;
import java.util.
Map;
/**
* Contains locking details (LockMode, Timeout and Scope).
*
* @author Scott Marlow
*/
public class
LockOptions implements
Serializable {
/**
* Represents LockMode.NONE (timeout + scope do not apply).
*/
public static final
LockOptions NONE = new
LockOptions(
LockMode.
NONE);
/**
* Represents LockMode.READ (timeout + scope do not apply).
*/
public static final
LockOptions READ = new
LockOptions(
LockMode.
READ);
/**
* Represents LockMode.UPGRADE (will wait forever for lock and scope of false meaning only entity is locked).
*/
@
SuppressWarnings("deprecation")
public static final
LockOptions UPGRADE = new
LockOptions(
LockMode.
UPGRADE);
/**
* Indicates that the database should not wait at all to acquire the pessimistic lock.
* @see #getTimeOut
*/
public static final int
NO_WAIT = 0;
/**
* Indicates that there is no timeout for the acquisition.
* @see #getTimeOut
*/
public static final int
WAIT_FOREVER = -1;
/**
* Indicates that rows that are already locked should be skipped.
* @see #getTimeOut()
*/
public static final int
SKIP_LOCKED = -2;
private
LockMode lockMode =
LockMode.
NONE;
private int
timeout =
WAIT_FOREVER;
private
Map<
String,
LockMode>
aliasSpecificLockModes;
private
Boolean followOnLocking;
/**
* Constructs a LockOptions with all default options.
*/
public
LockOptions() {
}
/**
* Constructs a LockOptions with the given lock mode.
*
* @param lockMode The lock mode to use
*/
public
LockOptions(
LockMode lockMode) {
this.
lockMode =
lockMode;
}
/**
* Retrieve the overall lock mode in effect for this set of options.
* <p/>
* In certain contexts (hql and criteria), lock-modes can be defined in an
* even more granular {@link #setAliasSpecificLockMode(String, LockMode) per-alias} fashion
*
* @return The overall lock mode.
*/
public
LockMode getLockMode() {
return
lockMode;
}
/**
* Set the overall {@link LockMode} to be used. The default is
* {@link LockMode#NONE}
*
* @param lockMode The new overall lock mode to use.
*
* @return this (for method chaining).
*/
public
LockOptions setLockMode(
LockMode lockMode) {
this.
lockMode =
lockMode;
return this;
}
/**
* Specify the {@link LockMode} to be used for a specific query alias.
*
* @param alias used to reference the LockMode.
* @param lockMode The lock mode to apply to the given alias
* @return this LockRequest instance for operation chaining.
*
* @see Query#setLockMode(String, LockMode)
* @see Criteria#setLockMode(LockMode)
* @see Criteria#setLockMode(String, LockMode)
*/
public
LockOptions setAliasSpecificLockMode(
String alias,
LockMode lockMode) {
if (
aliasSpecificLockModes == null ) {
aliasSpecificLockModes = new
LinkedHashMap<>();
}
aliasSpecificLockModes.
put(
alias,
lockMode );
return this;
}
/**
* Get the {@link LockMode} explicitly specified for the given alias via
* {@link #setAliasSpecificLockMode}
* <p/>
* Differs from {@link #getEffectiveLockMode} in that here we only return
* explicitly specified alias-specific lock modes.
*
* @param alias The alias for which to locate the explicit lock mode.
*
* @return The explicit lock mode for that alias.
*/
public
LockMode getAliasSpecificLockMode(
String alias) {
if (
aliasSpecificLockModes == null ) {
return null;
}
return
aliasSpecificLockModes.
get(
alias );
}
/**
* Determine the {@link LockMode} to apply to the given alias. If no
* mode was explicitly {@link #setAliasSpecificLockMode set}, the
* {@link #getLockMode overall mode} is returned. If the overall lock mode is
* <tt>null</tt> as well, {@link LockMode#NONE} is returned.
* <p/>
* Differs from {@link #getAliasSpecificLockMode} in that here we fallback to we only return
* the overall lock mode.
*
* @param alias The alias for which to locate the effective lock mode.
*
* @return The effective lock mode.
*/
public
LockMode getEffectiveLockMode(
String alias) {
LockMode lockMode =
getAliasSpecificLockMode(
alias );
if (
lockMode == null ) {
lockMode = this.
lockMode;
}
return
lockMode == null ?
LockMode.
NONE :
lockMode;
}
/**
* Does this LockOptions object define alias-specific lock modes?
*
* @return {@code true} if this LockOptions object define alias-specific lock modes; {@code false} otherwise.
*/
public boolean
hasAliasSpecificLockModes() {
return
aliasSpecificLockModes != null
&& !
aliasSpecificLockModes.
isEmpty();
}
/**
* Get the number of aliases that have specific lock modes defined.
*
* @return the number of explicitly defined alias lock modes.
*/
public int
getAliasLockCount() {
if (
aliasSpecificLockModes == null ) {
return 0;
}
return
aliasSpecificLockModes.
size();
}
/**
* Iterator for accessing Alias (key) and LockMode (value) as Map.Entry.
*
* @return Iterator for accessing the Map.Entry's
*/
public
Iterator<
Map.
Entry<
String,
LockMode>>
getAliasLockIterator() {
return
getAliasSpecificLocks().
iterator();
}
/**
* Iterable access to alias (key) and LockMode (value) as Map.Entry.
*
* @return Iterable for accessing the Map.Entry's
*/
public
Iterable<
Map.
Entry<
String,
LockMode>>
getAliasSpecificLocks() {
if (
aliasSpecificLockModes == null ) {
return
Collections.
emptyList();
}
return
aliasSpecificLockModes.
entrySet();
}
/**
* Currently needed for follow-on locking.
*
* @return The greatest of all requested lock modes.
*/
public
LockMode findGreatestLockMode() {
LockMode lockModeToUse =
getLockMode();
if (
lockModeToUse == null ) {
lockModeToUse =
LockMode.
NONE;
}
if (
aliasSpecificLockModes == null ) {
return
lockModeToUse;
}
for (
LockMode lockMode :
aliasSpecificLockModes.
values() ) {
if (
lockMode.
greaterThan(
lockModeToUse ) ) {
lockModeToUse =
lockMode;
}
}
return
lockModeToUse;
}
/**
* Retrieve the current timeout setting.
* <p/>
* The timeout is the amount of time, in milliseconds, we should instruct the database
* to wait for any requested pessimistic lock acquisition.
* <p/>
* {@link #NO_WAIT}, {@link #WAIT_FOREVER} or {@link #SKIP_LOCKED} represent 3 "magic" values.
*
* @return timeout in milliseconds, {@link #NO_WAIT}, {@link #WAIT_FOREVER} or {@link #SKIP_LOCKED}
*/
public int
getTimeOut() {
return
timeout;
}
/**
* Set the timeout setting.
* <p/>
* See {@link #getTimeOut} for a discussion of meaning.
*
* @param timeout The new timeout setting.
*
* @return this (for method chaining).
*
* @see #getTimeOut
*/
public
LockOptions setTimeOut(int
timeout) {
this.
timeout =
timeout;
return this;
}
private boolean
scope;
/**
* Retrieve the current lock scope setting.
* <p/>
* "scope" is a JPA defined term. It is basically a cascading of the lock to associations.
*
* @return true if locking will be extended to owned associations
*/
public boolean
getScope() {
return
scope;
}
/**
* Set the scope.
*
* @param scope The new scope setting
*
* @return this (for method chaining).
*/
public
LockOptions setScope(boolean
scope) {
this.
scope =
scope;
return this;
}
/**
* Retrieve the current follow-on-locking setting.
*
* @return true if follow-on-locking is enabled
*/
public
Boolean getFollowOnLocking() {
return
followOnLocking;
}
/**
* Set the the follow-on-locking setting.
* @param followOnLocking The new follow-on-locking setting
* @return this (for method chaining).
*/
public
LockOptions setFollowOnLocking(
Boolean followOnLocking) {
this.
followOnLocking =
followOnLocking;
return this;
}
/**
* Make a copy.
*
* @return The copy
*/
public
LockOptions makeCopy() {
final
LockOptions copy = new
LockOptions();
copy( this,
copy );
return
copy;
}
/**
* Perform a shallow copy.
*
* @param source Source for the copy (copied from)
* @param destination Destination for the copy (copied to)
*
* @return destination
*/
public static
LockOptions copy(
LockOptions source,
LockOptions destination) {
destination.
setLockMode(
source.
getLockMode() );
destination.
setScope(
source.
getScope() );
destination.
setTimeOut(
source.
getTimeOut() );
if (
source.
aliasSpecificLockModes != null ) {
destination.
aliasSpecificLockModes = new
HashMap<
String,
LockMode>(
source.
aliasSpecificLockModes );
}
destination.
setFollowOnLocking(
source.
getFollowOnLocking() );
return
destination;
}
}