[hibernate-commits] Hibernate SVN: r11286 - in branches/Branch_3_2/Hibernate3: src/org/hibernate/id and 6 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Mar 15 06:33:16 EDT 2007


Author: steve.ebersole at jboss.com
Date: 2007-03-15 06:33:16 -0400 (Thu, 15 Mar 2007)
New Revision: 11286

Added:
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/AccessCallback.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/DatabaseStructure.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/Optimizer.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/OptimizerFactory.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SegmentedTableGenerator.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SequenceStructure.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SequenceStyleGenerator.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/TableStructure.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/IdGenSuite.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Entity.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Entity.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java
Modified:
   branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/Dialect.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/H2Dialect.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/HSQLDialect.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/Oracle9Dialect.java
Log:
HHH-2471 : enhanced id generators

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/Dialect.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/Dialect.java	2007-03-14 23:23:30 UTC (rev 11285)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/Dialect.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -570,6 +570,18 @@
 	}
 
 	/**
+	 * Does this dialect support "pooled" sequences.  Not aware of a better
+	 * name for this.  Essentially can we specify the initial and increment values?
+	 *
+	 * @return True if such "pooled" sequences are supported; false otherwise.
+	 * @see #getCreateSequenceStrings(String, int, int)
+	 * @see #getCreateSequenceString(String, int, int)
+	 */
+	public boolean supportsPooledSequences() {
+		return false;
+	}
+
+	/**
 	 * Generate the appropriate select statement to to retreive the next value
 	 * of a sequence.
 	 * <p/>
@@ -604,12 +616,26 @@
 	 * @param sequenceName The name of the sequence
 	 * @return The sequence creation commands
 	 * @throws MappingException If sequences are not supported.
+	 * @deprecated Use {@link #getCreateSequenceString(String, int, int)} instead
 	 */
 	public String[] getCreateSequenceStrings(String sequenceName) throws MappingException {
 		return new String[] { getCreateSequenceString( sequenceName ) };
 	}
 
 	/**
+	 * An optional multi-line form for databases which {@link #supportsPooledSequences()}.
+	 *
+	 * @param sequenceName The name of the sequence
+	 * @param initialValue The initial value to apply to 'create sequence' statement
+	 * @param incrementSize The increment value to apply to 'create sequence' statement
+	 * @return The sequence creation commands
+	 * @throws MappingException If sequences are not supported.
+	 */
+	public String[] getCreateSequenceStrings(String sequenceName, int initialValue, int incrementSize) throws MappingException {
+		return new String[] { getCreateSequenceString( sequenceName, initialValue, incrementSize ) };
+	}
+
+	/**
 	 * Typically dialects which support sequences can create a sequence
 	 * with a single command.  This is convenience form of
 	 * {@link #getCreateSequenceStrings} to help facilitate that.
@@ -628,6 +654,30 @@
 	}
 
 	/**
+	 * Overloaded form of {@link #getCreateSequenceString(String)}, additionally
+	 * taking the initial value and increment size to be applied to the sequence
+	 * definition.
+	 * </p>
+	 * The default definition is to suffix {@link #getCreateSequenceString(String)}
+	 * with the string: " start with {initialValue} increment by {incrementSize}" where
+	 * {initialValue} and {incrementSize} are replacement placeholders.  Generally
+	 * dialects should only need to override this method if different key phrases
+	 * are used to apply the allocation information.
+	 *
+	 * @param sequenceName The name of the sequence
+	 * @param initialValue The initial value to apply to 'create sequence' statement
+	 * @param incrementSize The increment value to apply to 'create sequence' statement
+	 * @return The sequence creation command
+	 * @throws MappingException If sequences are not supported.
+	 */
+	protected String getCreateSequenceString(String sequenceName, int initialValue, int incrementSize) throws MappingException {
+		if ( supportsPooledSequences() ) {
+			return getCreateSequenceString( sequenceName ) + " start with " + initialValue + " increment by " + incrementSize;
+		}
+		throw new MappingException( "Dialect does not support pooled sequences" );
+	}
+
+	/**
 	 * The multiline script used to drop a sequence.
 	 *
 	 * @param sequenceName The name of the sequence
@@ -1650,7 +1700,7 @@
 	/**
 	 * Does the dialect support an exists statement in the select clause?
 	 *
-	 * @return
+	 * @return True if exists checks are allowed in the select clause; false otherwise.
 	 */
 	public boolean supportsExistsInSelect() {
 		return true;

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/H2Dialect.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/H2Dialect.java	2007-03-14 23:23:30 UTC (rev 11285)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/H2Dialect.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -4,6 +4,7 @@
 import java.sql.Types;
 
 import org.hibernate.Hibernate;
+import org.hibernate.MappingException;
 import org.hibernate.cfg.Environment;
 import org.hibernate.dialect.function.NoArgSQLFunction;
 import org.hibernate.dialect.function.StandardSQLFunction;
@@ -209,18 +210,20 @@
         return true;
     }
 
-    public String[] getCreateSequenceStrings(String sequenceName) {
-        return new String[] {
-                "create sequence " + sequenceName
-        };
-    }
 
-    public String[] getDropSequenceStrings(String sequenceName) {
-        return new String[] {
-                "drop sequence " + sequenceName
-        };
-    }
+	public boolean supportsPooledSequences() {
+		return true;
+	}
 
+	protected String getCreateSequenceString(String sequenceName) throws MappingException {
+		return "create sequence " + sequenceName;
+	}
+
+
+	protected String getDropSequenceString(String sequenceName) throws MappingException {
+		return "drop sequence " + sequenceName;
+	}
+
     public String getSelectSequenceNextValString(String sequenceName) {
         return "next value for " + sequenceName;
     }

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/HSQLDialect.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/HSQLDialect.java	2007-03-14 23:23:30 UTC (rev 11285)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/HSQLDialect.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -9,6 +9,7 @@
 import org.hibernate.LockMode;
 import org.hibernate.StaleObjectStateException;
 import org.hibernate.JDBCException;
+import org.hibernate.MappingException;
 import org.hibernate.engine.SessionImplementor;
 import org.hibernate.persister.entity.Lockable;
 import org.hibernate.util.ReflectHelper;
@@ -194,11 +195,23 @@
 		return false;
 	}
 
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public boolean supportsPooledSequences() {
+		return true;
+	}
+
 	public String[] getCreateSequenceStrings(String sequenceName) {
+		return getCreateSequenceStrings( sequenceName, 1, 1 );
+	}
+
+	public String[] getCreateSequenceStrings(String sequenceName, int initialValue, int incrementSize) {
 		return new String[] {
 				"create table dual_" + sequenceName + " (zero integer)",
 		        "insert into dual_" + sequenceName + " values (0)",
-		        "create sequence " + sequenceName + " start with 1"
+		        "create sequence " + sequenceName + " start with " + initialValue + " increment by " + incrementSize
 		};
 	}
 
@@ -226,10 +239,6 @@
 		}
 	}
 
-	public boolean supportsSequences() {
-		return true;
-	}
-
 	public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
 		return EXTRACTER;
 	}

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/Oracle9Dialect.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/Oracle9Dialect.java	2007-03-14 23:23:30 UTC (rev 11285)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/dialect/Oracle9Dialect.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -172,6 +172,10 @@
 		return true;
 	}
 
+	public boolean supportsPooledSequences() {
+		return true;
+	}
+
 	public boolean supportsLimit() {
 		return true;
 	}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/AccessCallback.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/AccessCallback.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/AccessCallback.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,16 @@
+package org.hibernate.id.enhanced;
+
+/**
+ * Contract for providing callback access to a {@link DatabaseStructure},
+ * typically from the {@link Optimizer}.
+ *
+ * @author Steve Ebersole
+ */
+public interface AccessCallback {
+	/**
+	 * Retrieve the next value from the underlying source.
+	 *
+	 * @return The next value.
+	 */
+	public long getNextValue();
+}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/DatabaseStructure.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/DatabaseStructure.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/DatabaseStructure.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,61 @@
+package org.hibernate.id.enhanced;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Encapsulates definition of the underlying data structure backing a
+ * sequence-style generator.
+ *
+ * @author Steve Ebersole
+ */
+public interface DatabaseStructure {
+	/**
+	 * The name of the database structure (table or sequence).
+	 * @return The structure name.
+	 */
+	public String getName();
+
+	/**
+	 * How many times has this structure been accessed through this reference?
+	 * @return The number of accesses.
+	 */
+	public int getTimesAccessed();
+
+	/**
+	 * The configured increment size
+	 * @return The configured increment size
+	 */
+	public int getIncrementSize();
+
+	/**
+	 * A callback to be able to get the next value from the underlying
+	 * structure as needed.
+	 *
+	 * @param session The session.
+	 * @return The next value.
+	 */
+	public AccessCallback buildCallback(SessionImplementor session);
+
+	/**
+	 * Prepare this structure for use.  Called sometime after instantiation,
+	 * but before first use.
+	 *
+	 * @param optimizer The optimizer being applied to the generator.
+	 */
+	public void prepare(Optimizer optimizer);
+
+	/**
+	 * Commands needed to create the underlying structures.
+	 * @param dialect The database dialect being used.
+	 * @return The creation commands.
+	 */
+	public String[] sqlCreateStrings(Dialect dialect);
+
+	/**
+	 * Commands needed to drop the underlying structures.
+	 * @param dialect The database dialect being used.
+	 * @return The drop commands.
+	 */
+	public String[] sqlDropStrings(Dialect dialect);
+}
\ No newline at end of file

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/Optimizer.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/Optimizer.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/Optimizer.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,53 @@
+package org.hibernate.id.enhanced;
+
+import java.io.Serializable;
+
+/**
+ * Performs optimization on an optimizable identifier generator.  Typically
+ * this optimization takes the form of trying to ensure we do not have to
+ * hit the database on each and every request to get an identifier value.
+ * <p/>
+ * Optimizers work on constructor injection.  They should provide
+ * a constructor with the following arguments <ol>
+ * <li>java.lang.Class - The return type for the generated values</li>
+ * <li>int - The increment size</li>
+ * </ol>
+ *
+ * @author Steve Ebersole
+ */
+public interface Optimizer {
+	/**
+	 * Generate an identifier value accounting for this specific optimization.
+	 *
+	 * @param callback Callback to access the underlying value source.
+	 * @return The generated identifier value.
+	 */
+	public Serializable generate(AccessCallback callback);
+
+	/**
+	 * A common means to access the last value obtained from the underlying
+	 * source.  This is intended for testing purposes, since accessing the
+	 * unerlying database source directly is much more difficult.
+	 *
+	 * @return The last value we obtained from the underlying source;
+	 * -1 indicates we have not yet consulted with the source.
+	 */
+	public long getLastSourceValue();
+
+	/**
+	 * Retrieves the defined increment size.
+	 *
+	 * @return The increment size.
+	 */
+	public int getIncrementSize();
+
+	/**
+	 * Are increments to be applied to the values stored in the underlying
+	 * value source?
+	 *
+	 * @return True if the values in the source are to be incremented
+	 * according to the defined increment size; false otherwise, in which
+	 * case the increment is totally an in memory construct.
+	 */
+	public boolean applyIncrementSizeToSourceValues();
+}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/OptimizerFactory.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/OptimizerFactory.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/OptimizerFactory.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,202 @@
+package org.hibernate.id.enhanced;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.id.IdentifierGeneratorFactory;
+
+/**
+ * Factory for {@link Optimizer} instances.
+ *
+ * @author Steve Ebersole
+ */
+public class OptimizerFactory {
+	private static final Log log = LogFactory.getLog( OptimizerFactory.class );
+
+	public static final String NONE = "none";
+	public static final String HILO = "hilo";
+	public static final String POOL = "pooled";
+
+	private static Class[] CTOR_SIG = new Class[] { Class.class, int.class };
+
+	public static Optimizer buildOptimizer(String type, Class returnClass, int incrementSize) {
+		String optimizerClassName;
+		if ( NONE.equals( type ) ) {
+			optimizerClassName = NoopOptimizer.class.getName();
+		}
+		else if ( HILO.equals( type ) ) {
+			optimizerClassName = HiLoOptimizer.class.getName();
+		}
+		else if ( POOL.equals( type ) ) {
+			optimizerClassName = PooledOptimizer.class.getName();
+		}
+		else {
+			optimizerClassName = type;
+		}
+
+		try {
+			Class optimizerClass = ReflectHelper.classForName( optimizerClassName );
+			Constructor ctor = optimizerClass.getConstructor( CTOR_SIG );
+			return ( Optimizer ) ctor.newInstance( new Object[] { returnClass, new Integer( incrementSize ) } );
+		}
+		catch( Throwable ignore ) {
+			// intentionally empty
+		}
+
+		// the default...
+		return new NoopOptimizer( returnClass, incrementSize );
+	}
+
+	public static abstract class OptimizerSupport implements Optimizer {
+		protected final Class returnClass;
+		protected final int incrementSize;
+
+		protected OptimizerSupport(Class returnClass, int incrementSize) {
+			if ( returnClass == null ) {
+				throw new HibernateException( "return class is required" );
+			}
+			this.returnClass = returnClass;
+			this.incrementSize = incrementSize;
+		}
+
+		protected Serializable make(long value) {
+			return IdentifierGeneratorFactory.createNumber( value, returnClass );
+		}
+
+		public Class getReturnClass() {
+			return returnClass;
+		}
+
+		public int getIncrementSize() {
+			return incrementSize;
+		}
+	}
+
+	public static class NoopOptimizer extends OptimizerSupport {
+		private long lastSourceValue = -1;
+
+		public NoopOptimizer(Class returnClass, int incrementSize) {
+			super( returnClass, incrementSize );
+		}
+
+		public Serializable generate(AccessCallback callback) {
+			if ( lastSourceValue == -1 ) {
+				while( lastSourceValue <= 0 ) {
+					lastSourceValue = callback.getNextValue();
+				}
+			}
+			else {
+				lastSourceValue = callback.getNextValue();
+			}
+			return make( lastSourceValue );
+		}
+
+		public long getLastSourceValue() {
+			return lastSourceValue;
+		}
+
+		public boolean applyIncrementSizeToSourceValues() {
+			return false;
+		}
+	}
+
+	public static class HiLoOptimizer extends OptimizerSupport {
+		private long lastSourceValue = -1;
+		private long value;
+		private long hiValue;
+
+		public HiLoOptimizer(Class returnClass, int incrementSize) {
+			super( returnClass, incrementSize );
+			if ( incrementSize < 1 ) {
+				throw new HibernateException( "increment size cannot be less than 1" );
+			}
+			if ( log.isTraceEnabled() ) {
+				log.trace( "creating hilo optimizer with [incrementSize=" + incrementSize + "; returnClass="  + returnClass.getName() + "]" );
+			}
+		}
+
+		public Serializable generate(AccessCallback callback) {
+			if ( lastSourceValue < 0 ) {
+				lastSourceValue = callback.getNextValue();
+				while ( lastSourceValue <= 0 ) {
+					lastSourceValue = callback.getNextValue();
+				}
+				hiValue = ( lastSourceValue * incrementSize ) + 1;
+				value = hiValue - incrementSize;
+			}
+			else if ( value >= hiValue ) {
+				lastSourceValue = callback.getNextValue();
+				hiValue = ( lastSourceValue * incrementSize ) + 1;
+			}
+			return make( value++ );
+		}
+
+
+		public long getLastSourceValue() {
+			return lastSourceValue;
+		}
+
+		public boolean applyIncrementSizeToSourceValues() {
+			return false;
+		}
+
+		public long getLastValue() {
+			return value - 1;
+		}
+
+		public long getHiValue() {
+			return hiValue;
+		}
+	}
+
+	public static class PooledOptimizer extends OptimizerSupport {
+		private long value;
+		private long hiValue = -1;
+
+		public PooledOptimizer(Class returnClass, int incrementSize) {
+			super( returnClass, incrementSize );
+			if ( incrementSize < 1 ) {
+				throw new HibernateException( "increment size cannot be less than 1" );
+			}
+			if ( log.isTraceEnabled() ) {
+				log.trace( "creating pooled optimizer with [incrementSize=" + incrementSize + "; returnClass="  + returnClass.getName() + "]" );
+			}
+		}
+
+		public Serializable generate(AccessCallback callback) {
+			if ( hiValue < 0 ) {
+				value = callback.getNextValue();
+				if ( value < 1 ) {
+					// unfortunately not really safe to normalize this
+					// to 1 as an initial value like we do the others
+					// because we would not be able to control this if
+					// we are using a sequence...
+					log.info( "pooled optimizer source reported [" + value + "] as the initial value; use of 1 or greater highly recommended" );
+				}
+				hiValue = callback.getNextValue();
+			}
+			else if ( value >= hiValue ) {
+				hiValue = callback.getNextValue();
+				value = hiValue - incrementSize;
+			}
+			return make( value++ );
+		}
+
+		public long getLastSourceValue() {
+			return hiValue;
+		}
+
+		public boolean applyIncrementSizeToSourceValues() {
+			return true;
+		}
+
+		public long getLastValue() {
+			return value - 1;
+		}
+	}
+}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SegmentedTableGenerator.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SegmentedTableGenerator.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SegmentedTableGenerator.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,304 @@
+package org.hibernate.id.enhanced;
+
+import java.sql.Types;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Properties;
+import java.util.HashMap;
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.engine.TransactionHelper;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.id.Configurable;
+import org.hibernate.type.Type;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.LockMode;
+import org.hibernate.mapping.Table;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.util.StringHelper;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * A "segmented" version of the enhanced table generator.  The term "segmented"
+ * refers to the fact that this table can hold multiple value generators,
+ * segmented by a key.
+ * <p/>
+ * Configuration parameters:
+ * <table>
+ * 	 <tr>
+ *     <td><b>NAME</b></td>
+ *     <td><b>DEFAULT</b></td>
+ *     <td><b>DESCRIPTION</b></td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #TABLE_PARAM}</td>
+ *     <td>{@link #DEF_TABLE}</td>
+ *     <td>The name of the table to use to store/retrieve values</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #VALUE_COLUMN_PARAM}</td>
+ *     <td>{@link #DEF_VALUE_COLUMN}</td>
+ *     <td>The name of column which holds the sequence value for the given segment</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #SEGMENT_COLUMN_PARAM}</td>
+ *     <td>{@link #DEF_SEGMENT_COLUMN}</td>
+ *     <td>The name of the column which holds the segment key</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #SEGMENT_VALUE_PARAM}</td>
+ *     <td>{@link #DEF_SEGMENT_VALUE}</td>
+ *     <td>The value indicating which segment is used by this generator; refers to values in the {@link #SEGMENT_COLUMN_PARAM} column</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #SEGMENT_LENGTH_PARAM}</td>
+ *     <td>{@link #DEF_SEGMENT_LENGTH}</td>
+ *     <td>The data length of the {@link #SEGMENT_COLUMN_PARAM} column; used for schema creation</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #INITIAL_PARAM}</td>
+ *     <td>{@link #DEFAULT_INITIAL_VALUE}</td>
+ *     <td>The initial value to be stored for the given segment</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #INCREMENT_PARAM}</td>
+ *     <td>{@link #DEFAULT_INCREMENT_SIZE}</td>
+ *     <td>The increment size for the underlying segment; see the discussion on {@link Optimizer} for more details.</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #OPT_PARAM}</td>
+ *     <td><i>depends on defined increment size</i></td>
+ *     <td>Allows explicit definition of which optimization strategy to use</td>
+ *   </tr>
+ * </table>
+ *
+ * @author Steve Ebersole
+ */
+public class SegmentedTableGenerator extends TransactionHelper implements PersistentIdentifierGenerator, Configurable {
+	private static final Log log = LogFactory.getLog( SegmentedTableGenerator.class );
+
+	public static final String TABLE_PARAM = "table_name";
+	public static final String DEF_TABLE = "hibernate_sequences";
+
+	public static final String VALUE_COLUMN_PARAM = "value_column_name";
+	public static final String DEF_VALUE_COLUMN = "next_val";
+
+	public static final String SEGMENT_COLUMN_PARAM = "segment_column_name";
+	public static final String DEF_SEGMENT_COLUMN = "sequence_name";
+
+	public static final String SEGMENT_VALUE_PARAM = "segment_value";
+	public static final String DEF_SEGMENT_VALUE = "default";
+
+	public static final String SEGMENT_LENGTH_PARAM = "segment_value_length";
+	public static final int DEF_SEGMENT_LENGTH = 255;
+
+	public static final String INITIAL_PARAM = "initial_value";
+	public static final int DEFAULT_INITIAL_VALUE = 1;
+
+	public static final String INCREMENT_PARAM = "increment_size";
+	public static final int DEFAULT_INCREMENT_SIZE = 1;
+
+	public static final String OPT_PARAM = "optimizer";
+
+
+	private String tableName;
+	private String valueColumnName;
+	private String segmentColumnName;
+	private String segmentValue;
+	private int segmentValueLength;
+	private int initialValue;
+	private int incrementSize;
+
+	private Type identifierType;
+
+	private String query;
+	private String insert;
+	private String update;
+
+	private Optimizer optimizer;
+
+	public String getTableName() {
+		return tableName;
+	}
+
+	public String getSegmentColumnName() {
+		return segmentColumnName;
+	}
+
+	public String getSegmentValue() {
+		return segmentValue;
+	}
+
+	public int getSegmentValueLength() {
+		return segmentValueLength;
+	}
+
+	public String getValueColumnName() {
+		return valueColumnName;
+	}
+
+	public Type getIdentifierType() {
+		return identifierType;
+	}
+
+	public int getInitialValue() {
+		return initialValue;
+	}
+
+	public int getIncrementSize() {
+		return incrementSize;
+	}
+
+	public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
+		tableName = PropertiesHelper.getString( TABLE_PARAM, params, DEF_TABLE );
+		if ( tableName.indexOf( '.' ) < 0 ) {
+			String schemaName = params.getProperty( SCHEMA );
+			String catalogName = params.getProperty( CATALOG );
+			tableName = Table.qualify( catalogName, schemaName, tableName );
+		}
+
+		segmentColumnName = PropertiesHelper.getString( SEGMENT_COLUMN_PARAM, params, DEF_SEGMENT_COLUMN );
+		segmentValue = params.getProperty( SEGMENT_VALUE_PARAM );
+		if ( StringHelper.isEmpty( segmentValue ) ) {
+			log.debug( "explicit segment value for id generator [" + tableName + '.' + segmentColumnName + "] suggested; using default [" + DEF_SEGMENT_VALUE + "]" );
+			segmentValue = DEF_SEGMENT_VALUE;
+		}
+		segmentValueLength = PropertiesHelper.getInt( SEGMENT_LENGTH_PARAM, params, DEF_SEGMENT_LENGTH );
+		valueColumnName = PropertiesHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
+		initialValue = PropertiesHelper.getInt( INITIAL_PARAM, params, DEFAULT_INITIAL_VALUE );
+		incrementSize = PropertiesHelper.getInt( INCREMENT_PARAM, params, DEFAULT_INCREMENT_SIZE );
+		identifierType = type;
+
+		String query = "select " + valueColumnName +
+				" from " + tableName + " tbl" +
+				" where tbl." + segmentColumnName + "=?";
+		HashMap lockMap = new HashMap();
+		lockMap.put( "tbl", LockMode.UPGRADE );
+		this.query = dialect.applyLocksToSql( query, lockMap, CollectionHelper.EMPTY_MAP );
+
+		update = "update " + tableName +
+				" set " + valueColumnName + "=? " +
+				" where " + valueColumnName + "=? and " + segmentColumnName + "=?";
+
+		insert = "insert into " + tableName + " (" + segmentColumnName + ", " + valueColumnName + ") " + " values (?,?)";
+
+		String defOptStrategy = incrementSize <= 1 ? OptimizerFactory.NONE : OptimizerFactory.POOL;
+		String optimizationStrategy = PropertiesHelper.getString( OPT_PARAM, params, defOptStrategy );
+		optimizer = OptimizerFactory.buildOptimizer( optimizationStrategy, identifierType.getReturnedClass(), incrementSize );
+	}
+
+	public synchronized Serializable generate(final SessionImplementor session, Object obj) {
+		return optimizer.generate(
+				new AccessCallback() {
+					public long getNextValue() {
+						return ( ( Number ) doWorkInNewTransaction( session ) ).longValue();
+					}
+				}
+		);
+	}
+
+	public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
+		int result;
+		int rows;
+		do {
+			sql = query;
+			SQL.debug( sql );
+			PreparedStatement queryPS = conn.prepareStatement( query );
+			try {
+				queryPS.setString( 1, segmentValue );
+				ResultSet queryRS = queryPS.executeQuery();
+				if ( !queryRS.next() ) {
+					PreparedStatement insertPS = null;
+					try {
+						result = initialValue;
+						sql = insert;
+						SQL.debug( sql );
+						insertPS = conn.prepareStatement( insert );
+						insertPS.setString( 1, segmentValue );
+						insertPS.setLong( 2, result );
+						insertPS.execute();
+					}
+					finally {
+						if ( insertPS != null ) {
+							insertPS.close();
+						}
+					}
+				}
+				else {
+					result = queryRS.getInt( 1 );
+				}
+				queryRS.close();
+			}
+			catch ( SQLException sqle ) {
+				log.error( "could not read or init a hi value", sqle );
+				throw sqle;
+			}
+			finally {
+				queryPS.close();
+			}
+
+			sql = update;
+			SQL.debug( sql );
+			PreparedStatement updatePS = conn.prepareStatement( update );
+			try {
+				long newValue = optimizer.applyIncrementSizeToSourceValues()
+						? result + incrementSize : result + 1;
+				updatePS.setLong( 1, newValue );
+				updatePS.setLong( 2, result );
+				updatePS.setString( 3, segmentValue );
+				rows = updatePS.executeUpdate();
+			}
+			catch ( SQLException sqle ) {
+				log.error( "could not update hi value in: " + tableName, sqle );
+				throw sqle;
+			}
+			finally {
+				updatePS.close();
+			}
+		}
+		while ( rows == 0 );
+		return new Integer( result );
+	}
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		return new String[] {
+				new StringBuffer()
+						.append( "create table " )
+						.append( tableName )
+						.append( " ( " )
+						.append( segmentColumnName )
+						.append( " " )
+						.append( dialect.getTypeName( Types.VARCHAR, segmentValueLength, 0, 0 ) )
+						.append( ",  " )
+						.append( valueColumnName )
+						.append( " " )
+						.append( dialect.getTypeName( Types.BIGINT ) )
+						.append( " ) " )
+						.toString()
+		};
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		StringBuffer sqlDropString = new StringBuffer().append( "drop table " );
+		if ( dialect.supportsIfExistsBeforeTableName() ) {
+			sqlDropString.append( "if exists " );
+		}
+		sqlDropString.append( tableName ).append( dialect.getCascadeConstraintsString() );
+		if ( dialect.supportsIfExistsAfterTableName() ) {
+			sqlDropString.append( " if exists" );
+		}
+		return new String[] { sqlDropString.toString() };
+	}
+
+	public Object generatorKey() {
+		return tableName;
+	}
+}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SequenceStructure.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SequenceStructure.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SequenceStructure.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,103 @@
+package org.hibernate.id.enhanced;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.HibernateException;
+
+/**
+ * Describes a sequence.
+ *
+ * @author Steve Ebersole
+ */
+public class SequenceStructure implements DatabaseStructure {
+	private static final Log log = LogFactory.getLog( SequenceStructure.class );
+
+	private final String sequenceName;
+	private final int initialValue;
+	private final int incrementSize;
+	private final String sql;
+	private boolean applyIncrementSizeToSourceValues;
+	private int accessCounter;
+
+	public SequenceStructure(Dialect dialect, String sequenceName, int initialValue, int incrementSize) {
+		this.sequenceName = sequenceName;
+		this.initialValue = initialValue;
+		this.incrementSize = incrementSize;
+		sql = dialect.getSequenceNextValString( sequenceName );
+	}
+
+	public String getName() {
+		return sequenceName;
+	}
+
+	public int getIncrementSize() {
+		return incrementSize;
+	}
+
+	public int getTimesAccessed() {
+		return accessCounter;
+	}
+
+	public AccessCallback buildCallback(final SessionImplementor session) {
+		return new AccessCallback() {
+			public long getNextValue() {
+				accessCounter++;
+				try {
+					PreparedStatement st = session.getBatcher().prepareSelectStatement( sql );
+					try {
+						ResultSet rs = st.executeQuery();
+						try {
+							rs.next();
+							long result = rs.getLong( 1 );
+							if ( log.isDebugEnabled() ) {
+								log.debug("Sequence identifier generated: " + result);
+							}
+							return result;
+						}
+						finally {
+							try {
+								rs.close();
+							}
+							catch( Throwable ignore ) {
+								// intentionally empty
+							}
+						}
+					}
+					finally {
+						session.getBatcher().closeStatement( st );
+					}
+
+				}
+				catch ( SQLException sqle) {
+					throw JDBCExceptionHelper.convert(
+							session.getFactory().getSQLExceptionConverter(),
+							sqle,
+							"could not get next sequence value",
+							sql
+					);
+				}
+			}
+		};
+	}
+
+	public void prepare(Optimizer optimizer) {
+		applyIncrementSizeToSourceValues = optimizer.applyIncrementSizeToSourceValues();
+	}
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		int sourceIncrementSize = applyIncrementSizeToSourceValues ? incrementSize : 1;
+		return dialect.getCreateSequenceStrings( sequenceName, initialValue, sourceIncrementSize );
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		return dialect.getDropSequenceStrings( sequenceName );
+	}
+}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SequenceStyleGenerator.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SequenceStyleGenerator.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/SequenceStyleGenerator.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,175 @@
+package org.hibernate.id.enhanced;
+
+import java.util.Properties;
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.id.Configurable;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.mapping.Table;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.type.Type;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Generates identifier values based on an sequence-style database structure.
+ * Variations range from actually using a sequence to using a table to mimic
+ * a sequence.  These variations are encapsulated by the {@link DatabaseStructure}
+ * interface internally.
+ * <p/>
+ * General configuration parameters:
+ * <table>
+ * 	 <tr>
+ *     <td><b>NAME</b></td>
+ *     <td><b>DEFAULT</b></td>
+ *     <td><b>DESCRIPTION</b></td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #SEQUENCE_PARAM}</td>
+ *     <td>{@link #DEF_SEQUENCE_NAME}</td>
+ *     <td>The name of the sequence/table to use to store/retrieve values</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #INITIAL_PARAM}</td>
+ *     <td>{@link #DEFAULT_INITIAL_VALUE}</td>
+ *     <td>The initial value to be stored for the given segment; the effect in terms of storage varies based on {@link Optimizer} and {@link DatabaseStructure}</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #INCREMENT_PARAM}</td>
+ *     <td>{@link #DEFAULT_INCREMENT_SIZE}</td>
+ *     <td>The increment size for the underlying segment; the effect in terms of storage varies based on {@link Optimizer} and {@link DatabaseStructure}</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #OPT_PARAM}</td>
+ *     <td><i>depends on defined increment size</i></td>
+ *     <td>Allows explicit definition of which optimization strategy to use</td>
+ *   </tr>
+ *     <td>{@link #FORCE_TBL_PARAM}</td>
+ *     <td><b><i>false<i/></b></td>
+ *     <td>Allows explicit definition of which optimization strategy to use</td>
+ *   </tr>
+ * </table>
+ * <p/>
+ * Configuration parameters used specifically when the underlying structure is a table:
+ * <table>
+ * 	 <tr>
+ *     <td><b>NAME</b></td>
+ *     <td><b>DEFAULT</b></td>
+ *     <td><b>DESCRIPTION</b></td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #VALUE_COLUMN_PARAM}</td>
+ *     <td>{@link #DEF_VALUE_COLUMN}</td>
+ *     <td>The name of column which holds the sequence value for the given segment</td>
+ *   </tr>
+ * </table>
+ *
+ * @author Steve Ebersole
+ */
+public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Configurable {
+	private static final Log log = LogFactory.getLog( SequenceStyleGenerator.class );
+
+	// general purpose parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	public static final String SEQUENCE_PARAM = "sequence_name";
+	public static final String DEF_SEQUENCE_NAME = "hibernate_sequence";
+
+	public static final String INITIAL_PARAM = "initial_value";
+	public static final int DEFAULT_INITIAL_VALUE = 1;
+
+	public static final String INCREMENT_PARAM = "increment_size";
+	public static final int DEFAULT_INCREMENT_SIZE = 1;
+
+	public static final String OPT_PARAM = "optimizer";
+
+	public static final String FORCE_TBL_PARAM = "force_table_use";
+
+
+	// table-specific parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	public static final String VALUE_COLUMN_PARAM = "value_column";
+	public static final String DEF_VALUE_COLUMN = "next_val";
+
+
+	// state ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	private DatabaseStructure databaseStructure;
+	private Optimizer optimizer;
+	private Type identifierType;
+
+	public DatabaseStructure getDatabaseStructure() {
+		return databaseStructure;
+	}
+
+	public Optimizer getOptimizer() {
+		return optimizer;
+	}
+
+	public Type getIdentifierType() {
+		return identifierType;
+	}
+
+
+	// Configurable implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
+		identifierType = type;
+		boolean forceTableUse = PropertiesHelper.getBoolean( FORCE_TBL_PARAM, params, false );
+
+		String sequenceName = PropertiesHelper.getString( SEQUENCE_PARAM, params, DEF_SEQUENCE_NAME );
+		if ( sequenceName.indexOf( '.' ) < 0 ) {
+			String schemaName = params.getProperty( SCHEMA );
+			String catalogName = params.getProperty( CATALOG );
+			sequenceName = Table.qualify( catalogName, schemaName, sequenceName );
+		}
+		int initialValue = PropertiesHelper.getInt( INITIAL_PARAM, params, DEFAULT_INITIAL_VALUE );
+		int incrementSize = PropertiesHelper.getInt( INCREMENT_PARAM, params, DEFAULT_INCREMENT_SIZE );
+
+		String valueColumnName = PropertiesHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
+
+		String defOptStrategy = incrementSize <= 1 ? OptimizerFactory.NONE : OptimizerFactory.POOL;
+		String optimizationStrategy = PropertiesHelper.getString( OPT_PARAM, params, defOptStrategy );
+		if ( OptimizerFactory.NONE.equals( optimizationStrategy ) && incrementSize > 1 ) {
+			log.warn( "config specified explicit optimizer of [" + OptimizerFactory.NONE + "], but [" + INCREMENT_PARAM + "=" + incrementSize + "; honoring optimizer setting" );
+			incrementSize = 1;
+		}
+		if ( dialect.supportsSequences() && !forceTableUse ) {
+			if ( OptimizerFactory.POOL.equals( optimizationStrategy ) && !dialect.supportsPooledSequences() ) {
+				// TODO : may even be better to fall back to a pooled table strategy here so that the db stored values remain consistent...
+				optimizationStrategy = OptimizerFactory.HILO;
+			}
+			databaseStructure = new SequenceStructure( dialect, sequenceName, initialValue, incrementSize );
+		}
+		else {
+			databaseStructure = new TableStructure( dialect, sequenceName, valueColumnName, initialValue, incrementSize );
+		}
+
+		optimizer = OptimizerFactory.buildOptimizer( optimizationStrategy, identifierType.getReturnedClass(), incrementSize );
+		databaseStructure.prepare( optimizer );
+	}
+
+
+	// IdentifierGenerator implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
+		return optimizer.generate( databaseStructure.buildCallback( session ) );
+	}
+
+
+	// PersistentIdentifierGenerator implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Object generatorKey() {
+		return databaseStructure.getName();
+	}
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		return databaseStructure.sqlCreateStrings( dialect );
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		return databaseStructure.sqlDropStrings( dialect );
+	}
+
+}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/TableStructure.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/TableStructure.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/id/enhanced/TableStructure.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,144 @@
+package org.hibernate.id.enhanced;
+
+import java.sql.Types;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.LockMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TransactionHelper;
+import org.hibernate.id.IdentifierGenerationException;
+
+/**
+ * Describes a table used to mimic sequence behavior
+ *
+ * @author Steve Ebersole
+ */
+public class TableStructure extends TransactionHelper implements DatabaseStructure {
+	private static final Log log = LogFactory.getLog( TableStructure.class );
+	private static final Log SQL_LOG = LogFactory.getLog( "org.hibernate.SQL" );
+
+	private final String tableName;
+	private final String valueColumnName;
+	private final int initialValue;
+	private final int incrementSize;
+	private final String select;
+	private final String update;
+	private boolean applyIncrementSizeToSourceValues;
+	private int accessCounter;
+
+	public TableStructure(Dialect dialect, String tableName, String valueColumnName, int initialValue, int incrementSize) {
+		this.tableName = tableName;
+		this.initialValue = initialValue;
+		this.incrementSize = incrementSize;
+		this.valueColumnName = valueColumnName;
+
+		select = "select " + valueColumnName + " id_val" +
+				" from " + dialect.appendLockHint( LockMode.UPGRADE, tableName ) +
+				dialect.getForUpdateString();
+
+		update = "update " + tableName +
+				" set " + valueColumnName + "= ?" +
+				" where " + valueColumnName + "=?";
+	}
+
+	public String getName() {
+		return tableName;
+	}
+
+	public int getIncrementSize() {
+		return incrementSize;
+	}
+
+	public int getTimesAccessed() {
+		return accessCounter;
+	}
+
+	public void prepare(Optimizer optimizer) {
+		applyIncrementSizeToSourceValues = optimizer.applyIncrementSizeToSourceValues();
+	}
+
+	public AccessCallback buildCallback(final SessionImplementor session) {
+		return new AccessCallback() {
+			public long getNextValue() {
+				return ( ( Number ) doWorkInNewTransaction( session ) ).longValue();
+			}
+		};
+	}
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		return new String[] {
+				"create table " + tableName + " ( " + valueColumnName + " " + dialect.getTypeName( Types.BIGINT ) + " )",
+				"insert into " + tableName + " values ( " + initialValue + " )"
+		};
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		StringBuffer sqlDropString = new StringBuffer().append( "drop table " );
+		if ( dialect.supportsIfExistsBeforeTableName() ) {
+			sqlDropString.append( "if exists " );
+		}
+		sqlDropString.append( tableName ).append( dialect.getCascadeConstraintsString() );
+		if ( dialect.supportsIfExistsAfterTableName() ) {
+			sqlDropString.append( " if exists" );
+		}
+		return new String[] { sqlDropString.toString() };
+	}
+
+	protected Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
+		long result;
+		int rows;
+		do {
+			sql = select;
+			SQL_LOG.debug( sql );
+			PreparedStatement qps = conn.prepareStatement( select );
+			try {
+				ResultSet rs = qps.executeQuery();
+				if ( !rs.next() ) {
+					String err = "could not read a hi value - you need to populate the table: " + tableName;
+					log.error( err );
+					throw new IdentifierGenerationException( err );
+				}
+				result = rs.getLong( 1 );
+				rs.close();
+			}
+			catch ( SQLException sqle ) {
+				log.error( "could not read a hi value", sqle );
+				throw sqle;
+			}
+			finally {
+				qps.close();
+			}
+
+			sql = update;
+			SQL_LOG.debug( sql );
+			PreparedStatement ups = conn.prepareStatement( update );
+			try {
+				int increment = applyIncrementSizeToSourceValues ? incrementSize : 1;
+				ups.setLong( 1, result + increment );
+				ups.setLong( 2, result );
+				rows = ups.executeUpdate();
+			}
+			catch ( SQLException sqle ) {
+				log.error( "could not update hi value in: " + tableName, sqle );
+				throw sqle;
+			}
+			finally {
+				ups.close();
+			}
+		} while ( rows == 0 );
+
+		accessCounter++;
+
+		return new Long( result );
+	}
+
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/IdGenSuite.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/IdGenSuite.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/IdGenSuite.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,37 @@
+package org.hibernate.test.idgen;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.idgen.enhanced.sequence.BasicSequenceTest;
+import org.hibernate.test.idgen.enhanced.sequence.HiLoSequenceTest;
+import org.hibernate.test.idgen.enhanced.sequence.PooledSequenceTest;
+import org.hibernate.test.idgen.enhanced.table.BasicTableTest;
+import org.hibernate.test.idgen.enhanced.table.HiLoTableTest;
+import org.hibernate.test.idgen.enhanced.table.PooledTableTest;
+import org.hibernate.test.idgen.enhanced.OptimizerUnitTest;
+import org.hibernate.test.idgen.enhanced.SequenceStyleConfigUnitTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class IdGenSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "id generators" );
+
+		suite.addTest( OptimizerUnitTest.suite() );
+		suite.addTest( SequenceStyleConfigUnitTest.suite() );
+
+		suite.addTest( BasicSequenceTest.suite() );
+		suite.addTest( HiLoSequenceTest.suite() );
+		suite.addTest( PooledSequenceTest.suite() );
+		
+		suite.addTest( BasicTableTest.suite() );
+		suite.addTest( HiLoTableTest.suite() );
+		suite.addTest( PooledTableTest.suite() );
+
+		return suite;
+	}
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,154 @@
+package org.hibernate.test.idgen.enhanced;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.id.enhanced.Optimizer;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.AccessCallback;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class OptimizerUnitTest extends UnitTestCase {
+	public OptimizerUnitTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new TestSuite( OptimizerUnitTest.class );
+	}
+
+	public void testBasicNoOptimizerUsage() {
+		// test historic sequence behavior, where the initial values start at 1...
+		SourceMock sequence = new SourceMock( 1 );
+		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 );
+		for ( int i = 1; i < 11; i++ ) {
+			final Long next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 10, sequence.getTimesCalled() );
+		assertEquals( 10, sequence.getCurrentValue() );
+
+		// test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value)
+		sequence = new SourceMock( 0 );
+		optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 );
+		for ( int i = 1; i < 11; i++ ) {
+			final Long next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 11, sequence.getTimesCalled() ); // an extra time to get to 1 initially
+		assertEquals( 10, sequence.getCurrentValue() );
+	}
+
+	public void testBasicHiLoOptimizerUsage() {
+		int increment = 10;
+		Long next;
+
+		// test historic sequence behavior, where the initial values start at 1...
+		SourceMock sequence = new SourceMock( 1 );
+		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment );
+		for ( int i = 1; i <= increment; i++ ) {
+			next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 1, sequence.getTimesCalled() ); // once to initialze state
+		assertEquals( 1, sequence.getCurrentValue() );
+		// force a "clock over"
+		next = ( Long ) optimizer.generate( sequence );
+		assertEquals( 11, next.intValue() );
+		assertEquals( 2, sequence.getTimesCalled() );
+		assertEquals( 2, sequence.getCurrentValue() );
+
+		// test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value)
+		sequence = new SourceMock( 0 );
+		optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment );
+		for ( int i = 1; i <= increment; i++ ) {
+			next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 2, sequence.getTimesCalled() ); // here have have an extra call to get to 1 initially
+		assertEquals( 1, sequence.getCurrentValue() );
+		// force a "clock over"
+		next = ( Long ) optimizer.generate( sequence );
+		assertEquals( 11, next.intValue() );
+		assertEquals( 3, sequence.getTimesCalled() );
+		assertEquals( 2, sequence.getCurrentValue() );
+	}
+
+	public void testBasicPooledOptimizerUsage() {
+		Long next;
+		// test historic sequence behavior, where the initial values start at 1...
+		SourceMock sequence = new SourceMock( 1, 10 );
+		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, 10 );
+		for ( int i = 1; i < 11; i++ ) {
+			next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 2, sequence.getTimesCalled() ); // twice to initialze state
+		assertEquals( 11, sequence.getCurrentValue() );
+		// force a "clock over"
+		next = ( Long ) optimizer.generate( sequence );
+		assertEquals( 11, next.intValue() );
+		assertEquals( 3, sequence.getTimesCalled() );
+		assertEquals( 21, sequence.getCurrentValue() );
+	}
+
+	private static class SourceMock implements AccessCallback {
+		private long value;
+		private int increment;
+		private int timesCalled = 0;
+
+		public SourceMock(long initialValue) {
+			this( initialValue, 1 );
+		}
+
+		public SourceMock(long initialValue, int increment) {
+			this.increment = increment;
+			this.value = initialValue - increment;
+		}
+
+		public long getNextValue() {
+			timesCalled++;
+			return ( value += increment );
+		}
+
+		public int getTimesCalled() {
+			return timesCalled;
+		}
+
+		public long getCurrentValue() {
+			return value;
+		}
+	}
+
+//	public void testNoopDumping() {
+//		SourceMock sequence = new SourceMock( 1 );
+//		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 );
+//		for ( int i = 1; i <= 41; i++ ) {
+//			System.out.println( i + " => " + optimizer.generate( sequence ) + " (" + sequence.getCurrentValue() + ")" );
+//		}
+//	}
+//
+//	public void testHiLoDumping() {
+//		int increment = 10;
+//		SourceMock sequence = new SourceMock( 1 );
+//		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment );
+//		for ( int i = 1; i <= 41; i++ ) {
+//			System.out.println( i + " => " + optimizer.generate( sequence ) + " (" + sequence.getCurrentValue() + ")" );
+//		}
+//	}
+//
+//	public void testPooledDumping() {
+//		int increment = 10;
+//		SourceMock sequence = new SourceMock( 1, increment );
+//		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, increment );
+//		for ( int i = 1; i <= 41; i++ ) {
+//			System.out.println( i + " => " + optimizer.generate( sequence ) + " (" + sequence.getCurrentValue() + ")" );
+//		}
+//	}
+
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,180 @@
+package org.hibernate.test.idgen.enhanced;
+
+import java.util.Properties;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.id.enhanced.SequenceStructure;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.TableStructure;
+import org.hibernate.Hibernate;
+import org.hibernate.MappingException;
+
+/**
+ * Tests that SequenceStyleGenerator configures itself as expected
+ * in various scenarios
+ *
+ * @author Steve Ebersole
+ */
+public class SequenceStyleConfigUnitTest extends UnitTestCase {
+	public SequenceStyleConfigUnitTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new TestSuite( SequenceStyleConfigUnitTest.class );
+	}
+
+	/**
+	 * Test all params defaulted with a dialect supporting sequences
+	 */
+	public void testDefaultedSequenceBackedConfiguration() {
+		Dialect dialect = new SequenceDialect();
+		Properties props = new Properties();
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test all params defaulted with a dialect which does not support sequences
+	 */
+	public void testDefaultedTableBackedConfiguration() {
+		Dialect dialect = new TableDialect();
+		Properties props = new Properties();
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+
+		assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test default optimizer selection for sequence backed generators
+	 * based on the configured increment size; both in the case of the
+	 * dialect supporting pooled sequences (pooled) and not (hilo)
+	 */
+	public void testDefaultOptimizerBasedOnIncrementBackedBySequence() {
+		Properties props = new Properties();
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
+
+		// for dialects which do not support pooled sequences, we default to hilo
+		Dialect dialect = new SequenceDialect();
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+
+		// for dialects which do support pooled sequences, we default to pooled
+		dialect = new PooledSequenceDialect();
+		generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test default optimizer selection for table backed generators
+	 * based on the configured increment size.  Here we always prefer
+	 * pooled.
+	 */
+	public void testDefaultOptimizerBasedOnIncrementBackedByTable() {
+		Properties props = new Properties();
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
+		Dialect dialect = new TableDialect();
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test forcing of table as backing strucuture with dialect supporting sequences
+	 */
+	public void testForceTableUse() {
+		Dialect dialect = new SequenceDialect();
+		Properties props = new Properties();
+		props.setProperty( SequenceStyleGenerator.FORCE_TBL_PARAM, "true" );
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test explicitly specifying both optimizer and increment
+	 */
+	public void testExplicitOptimizerWithExplicitIncrementSize() {
+		// with sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		Dialect dialect = new SequenceDialect();
+
+		// optimizer=none w/ increment > 1 => should honor optimizer
+		Properties props = new Properties();
+		props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.NONE );
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( 1, generator.getOptimizer().getIncrementSize() );
+		assertEquals( 1, generator.getDatabaseStructure().getIncrementSize() );
+
+		// optimizer=hilo w/ increment > 1 => hilo
+		props = new Properties();
+		props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.HILO );
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( 20, generator.getOptimizer().getIncrementSize() );
+		assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() );
+
+		// optimizer=pooled w/ increment > 1 => hilo
+		props = new Properties();
+		props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.POOL );
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
+		generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( 20, generator.getOptimizer().getIncrementSize() );
+		assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() );
+
+	}
+
+	private static class TableDialect extends Dialect {
+		public boolean supportsSequences() {
+			return false;
+		}
+	}
+
+	private static class SequenceDialect extends Dialect {
+		public boolean supportsSequences() {
+			return true;
+		}
+		public boolean supportsPooledSequences() {
+			return false;
+		}
+		public String getSequenceNextValString(String sequenceName) throws MappingException {
+			return "";
+		}
+	}
+
+	private static class PooledSequenceDialect extends SequenceDialect {
+		public boolean supportsPooledSequences() {
+			return true;
+		}
+	}
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced sequence-based identifier
+    generator, with no performance optimizations (the DB is hit
+    everytime when generating a value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.sequence">
+
+    <class name="Entity" table="ID_SEQ_BSC_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="sequence_name">ID_SEQ_BSC_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">1</param>
+                <param name="optimizer">none</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,57 @@
+package org.hibernate.test.idgen.enhanced.sequence;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.Session;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class BasicSequenceTest extends FunctionalTestCase {
+	public BasicSequenceTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/sequence/Basic.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BasicSequenceTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+
+		int count = 5;
+		Entity[] entities = new Entity[count];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			long expectedId = i + 1;
+			assertEquals( expectedId, entities[i].getId().longValue() );
+			assertEquals( expectedId, generator.getDatabaseStructure().getTimesAccessed() );
+			assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() );
+		}
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+
+	}
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Entity.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Entity.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Entity.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,34 @@
+package org.hibernate.test.idgen.enhanced.sequence;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Entity {
+	private Long id;
+	private String name;
+
+	public Entity() {
+	}
+
+	public Entity(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced sequence-based identifier
+    generator, using a hilo algorithm as the optimization (to
+    avoid hitting the database to generate each value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.sequence">
+
+    <class name="Entity" table="ID_SEQ_HILO_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="sequence_name">ID_SEQ_HILO_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">hilo</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,67 @@
+package org.hibernate.test.idgen.enhanced.sequence;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.Session;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class HiLoSequenceTest extends FunctionalTestCase {
+	public HiLoSequenceTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/sequence/HiLo.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( HiLoSequenceTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.HiLoOptimizer optimizer = ( OptimizerFactory.HiLoOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			assertEquals( 1, generator.getDatabaseStructure().getTimesAccessed() ); // initialization
+			assertEquals( 1, optimizer.getLastSourceValue() ); // initialization
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getHiValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization
+		assertEquals( 2, optimizer.getLastSourceValue() ); // initialization
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() );
+
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced sequence-based identifier
+    generator, using a pooled algorithm as the optimization (to
+    avoid hitting the database to generate each value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.sequence">
+
+    <class name="Entity" table="ID_SEQ_POOL_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="sequence_name">ID_SEQ_POOL_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">pooled</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,65 @@
+package org.hibernate.test.idgen.enhanced.sequence;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PooledSequenceTest extends FunctionalTestCase {
+	public PooledSequenceTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/sequence/Pooled.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PooledSequenceTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.PooledOptimizer optimizer = ( OptimizerFactory.PooledOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization calls seq twice
+			assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls seq twice
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getLastSourceValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		assertEquals( 3, generator.getDatabaseStructure().getTimesAccessed() ); // initialization (2) + clock over
+		assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced sequence-based identifier
+    generator, with no performance optimizations (the DB is hit
+    everytime when generating a value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.table">
+
+    <class name="Entity" table="ID_SEQ_TBL_BSC_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="table_name">ID_SEQ_TBL_BSC_SEQ</param>
+                <param name="value_column">hi_val</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">1</param>
+                <param name="optimizer">none</param>
+                <param name="force_tbl_use">true</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,57 @@
+package org.hibernate.test.idgen.enhanced.table;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class BasicTableTest extends DatabaseSpecificFunctionalTestCase {
+	public BasicTableTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/table/Basic.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BasicTableTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+
+		int count = 5;
+		Entity[] entities = new Entity[count];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			long expectedId = i + 1;
+			assertEquals( expectedId, entities[i].getId().longValue() );
+			assertEquals( expectedId, generator.getDatabaseStructure().getTimesAccessed() );
+			assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() );
+		}
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+
+	}
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Entity.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Entity.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Entity.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,34 @@
+package org.hibernate.test.idgen.enhanced.table;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Entity {
+	private Long id;
+	private String name;
+
+	public Entity() {
+	}
+
+	public Entity(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced table-based identifier
+    generator, using a hilo algorithm as the optimization (to
+    avoid hitting the database to generate each value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.table">
+
+    <class name="Entity" table="ID_SEQ_TBL_HILO_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="table_name">ID_SEQ_TBL_HILO_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">hilo</param>
+                <param name="force_tbl_use">true</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,69 @@
+package org.hibernate.test.idgen.enhanced.table;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class HiLoTableTest extends DatabaseSpecificFunctionalTestCase {
+	public HiLoTableTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/table/HiLo.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( HiLoTableTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.HiLoOptimizer optimizer = ( OptimizerFactory.HiLoOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			long expectedId = i + 1;
+			assertEquals( expectedId, entities[i].getId().longValue() );
+			assertEquals( 1, generator.getOptimizer().getLastSourceValue() );
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getHiValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		long expectedId = optimizer.getIncrementSize() + 1;
+		assertEquals( expectedId, entities[ optimizer.getIncrementSize() ].getId().longValue() );
+		assertEquals( 2, optimizer.getLastSourceValue() ); // initialization + clokc-over
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() );
+
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced table-based identifier
+    generator, using a hilo algorithm as the optimization (to
+    avoid hitting the database to generate each value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.table">
+
+    <class name="Entity" table="ID_SEQ_TBL_POOL_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="table_name">ID_SEQ_TBL_POOL_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">pooled</param>
+                <param name="force_tbl_use">true</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java	2007-03-15 10:33:16 UTC (rev 11286)
@@ -0,0 +1,69 @@
+package org.hibernate.test.idgen.enhanced.table;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PooledTableTest extends DatabaseSpecificFunctionalTestCase {
+	public PooledTableTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/table/Pooled.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PooledTableTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.PooledOptimizer optimizer = ( OptimizerFactory.PooledOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			long expectedId = i + 1;
+			assertEquals( expectedId, entities[i].getId().longValue() );
+			assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization calls table twice
+			assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls table twice
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getLastSourceValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		long expectedId = optimizer.getIncrementSize() + 1;
+		assertEquals( expectedId, entities[ optimizer.getIncrementSize() ].getId().longValue() );
+		assertEquals( 3, generator.getDatabaseStructure().getTimesAccessed() ); // initialization (2) + clock over
+		assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}




More information about the hibernate-commits mailing list