//$Id: Versioning.java 10858 2006-11-21 23:28:29Z [email protected] $
package org.hibernate.engine;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.VersionType;
/**
* Utilities for dealing with optimisitic locking values.
*
* @author Gavin King
*/
public final class Versioning {
/**
* Apply no optimistic locking
*/
public static final int OPTIMISTIC_LOCK_NONE = -1;
/**
* Apply optimisitc locking based on the defined version or timestamp
* property.
*/
public static final int OPTIMISTIC_LOCK_VERSION = 0;
/**
* Apply optimisitc locking based on the a current vs. snapshot comparison
* of <b>all</b> properties.
*/
public static final int OPTIMISTIC_LOCK_ALL = 2;
/**
* Apply optimisitc locking based on the a current vs. snapshot comparison
* of <b>dirty</b> properties.
*/
public static final int OPTIMISTIC_LOCK_DIRTY = 1;
private static final Log log = LogFactory.getLog( Versioning.class );
/**
* Private constructor disallowing instantiation.
*/
private Versioning() {}
/**
* Create an initial optimisitc locking value according the {@link VersionType}
* contract for the version property.
*
* @param versionType The version type.
* @param session The originating session
* @return The initial optimisitc locking value
*/
private static Object seed(VersionType versionType, SessionImplementor session) {
Object seed = versionType.seed( session );
if ( log.isTraceEnabled() ) log.trace("Seeding: " + seed);
return seed;
}
/**
* Create an initial optimisitc locking value according the {@link VersionType}
* contract for the version property <b>if required</b> and inject it into
* the snapshot state.
*
* @param fields The current snapshot state
* @param versionProperty The index of the version property
* @param versionType The version type
* @param session The orginating session
* @return True if we injected a new version value into the fields array; false
* otherwise.
*/
public static boolean seedVersion(
Object[] fields,
int versionProperty,
VersionType versionType,
SessionImplementor session) {
Object initialVersion = fields[versionProperty];
if (
initialVersion==null ||
// This next bit is to allow for both unsaved-value="negative"
// and for "older" behavior where version number did not get
// seeded if it was already set in the object
// TODO: shift it into unsaved-value strategy
( (initialVersion instanceof Number) && ( (Number) initialVersion ).longValue()<0 )
) {
fields[versionProperty] = seed( versionType, session );
return true;
}
else {
if ( log.isTraceEnabled() ) {
log.trace( "using initial version: " + initialVersion );
}
return false;
}
}
/**
* Generate the next increment in the optimisitc locking value according
* the {@link VersionType} contract for the version property.
*
* @param version The current version
* @param versionType The version type
* @param session The originating session
* @return The incremented optimistic locking value.
*/
public static Object increment(Object version, VersionType versionType, SessionImplementor session) {
Object next = versionType.next( version, session );
if ( log.isTraceEnabled() ) {
log.trace(
"Incrementing: " +
versionType.toLoggableString( version, session.getFactory() ) +
" to " +
versionType.toLoggableString( next, session.getFactory() )
);
}
return next;
}
/**
* Inject the optimisitc locking value into the entity state snapshot.
*
* @param fields The state snapshot
* @param version The optimisitc locking value
* @param persister The entity persister
*/
public static void setVersion(Object[] fields, Object version, EntityPersister persister) {
if ( !persister.isVersioned() ) {
return;
}
fields[ persister.getVersionProperty() ] = version;
}
/**
* Extract the optimisitc locking value out of the entity state snapshot.
*
* @param fields The state snapshot
* @param persister The entity persister
* @return The extracted optimisitc locking value
*/
public static Object getVersion(Object[] fields, EntityPersister persister) {
if ( !persister.isVersioned() ) {
return null;
}
return fields[ persister.getVersionProperty() ];
}
/**
* Do we need to increment the version number, given the dirty properties?
*
* @param dirtyProperties The array of property indexes which were deemed dirty
* @param hasDirtyCollections Were any collections found to be dirty (structurally changed)
* @param propertyVersionability An array indicating versionability of each property.
* @return True if a version increment is required; false otherwise.
*/
public static boolean isVersionIncrementRequired(
final int[] dirtyProperties,
final boolean hasDirtyCollections,
final boolean[] propertyVersionability) {
if ( hasDirtyCollections ) {
return true;
}
for ( int i = 0; i < dirtyProperties.length; i++ ) {
if ( propertyVersionability[ dirtyProperties[i] ] ) {
return true;
}
}
return false;
}
}
|