FileDocCategorySizeDatePackage
JTATableIdGenerator.javaAPI DocJBoss 4.2.111159Fri Jul 13 20:53:58 BST 2007org.jboss.ejb3.entity

JTATableIdGenerator

public class JTATableIdGenerator extends Object implements org.hibernate.id.PersistentIdentifierGenerator, org.hibernate.id.Configurable
A hilo IdentifierGenerator that uses a database table to store the last generated value.

This implementation is solely for use inside JBoss using JTA for transactions.

TODO implement sequence allocation

author
Klaus Richarz.
version
$Revision: 57207 $
see
org.hibernate.id.TableGenerator
see
javax.persistence.TableGenerator

Fields Summary
public static final String
COLUMN
The column parameter
public static final String
DEFAULT_COLUMN_NAME
Default column name
public static final String
TABLE
The table parameter
public static final String
DEFAULT_TABLE_NAME
Default table name
public static final String
ALLOCATION_SIZE
The allocation-size parameter
public static final int
DEFAULT_ALLOCATION_SIZE
Default allocation-size
private static final Log
log
logger for JTATableGenerator
private String
tableName
Holds the name where this generator gets its sequence from
private String
columnName
Holds the name ofthe column where the next sequence value is stored
private String
query
Holds the sql query to retrieve the next high value
private String
update
Holds the sql query to increment the sequence
private org.hibernate.transaction.TransactionManagerLookup
transactionManagerLookup
Holds the transaction manager lookup object
private Class
returnClass
Holds the class type for the sequence value returned by generate()
private int
allocationSize
Holds the size for the sequence increment. The allocated sequences are managed in memory and may be lost if the system stops.
Constructors Summary
Methods Summary
public voidconfigure(org.hibernate.type.Type type, java.util.Properties params, org.hibernate.dialect.Dialect dialect)


          
   
      this.tableName = PropertiesHelper.getString(TABLE, params, DEFAULT_TABLE_NAME);
      this.columnName = PropertiesHelper.getString(COLUMN, params, DEFAULT_COLUMN_NAME);
      this.allocationSize = PropertiesHelper.getInt(ALLOCATION_SIZE, params, DEFAULT_ALLOCATION_SIZE);
      String schemaName = params.getProperty(SCHEMA);
      String catalogName = params.getProperty(CATALOG);

      if (true) throw new RuntimeException("DOES ANYBODY USE THIS?  It IS CURRENTLY BROKEN");

      /*
      getSchemaSeparator does not exist in hibernate anymore since 3.1 release

      // prepare table name
      if (tableName.indexOf(dialect.getSchemaSeparator()) < 0)
      {
         tableName = Table.qualify(catalogName, schemaName, tableName, dialect.getSchemaSeparator());
      }
      */

      // prepare SQL statements
      query = "select " +
              columnName +
              " from " +
              dialect.appendLockHint(LockMode.UPGRADE, tableName) +
              dialect.getForUpdateString();
      update = "update " +
               tableName +
               " set " +
               columnName +
               " = ? where " +
               columnName +
               " = ?";

      // set up transaction manager lookup
      // only JBoss transaction manager is supported
      transactionManagerLookup = new JBossTransactionManagerLookup();

      // set the sequence type that should be returned
      returnClass = type.getReturnedClass();

      // debug chosen configuration
      if (log.isDebugEnabled())
      {
         log.debug("configuring id generator: " + this.getClass().getName());
         log.debug("tableName=" + tableName);
         log.debug("columnName=" + columnName);
         log.debug("allocationSize=" + allocationSize);
         log.debug("query=" + query);
         log.debug("update=" + update);
         log.debug("returnClass=" + returnClass);
      }
   
public synchronized java.io.Serializablegenerate(org.hibernate.engine.SessionImplementor session, java.lang.Object object)

      // get TransactionManager from JNDI
      // no JNDI properties provided -> we are in the container
      TransactionManager tm = transactionManagerLookup.getTransactionManager(new Properties());
      Transaction surroundingTransaction = null;  // for resuming in finally block
      Connection conn = null; // for ressource cleanup
      String sql = null; // for exception
      try
      {
         long result; // holds the resulting sequence value

         // prepare a new transaction context for the generator
         surroundingTransaction = tm.suspend();
         if (log.isDebugEnabled())
         {
            log.debug("surrounding tx suspended");
         }
         tm.begin();

         // get connection from managed environment
         conn = session.getBatcher().openConnection();

         // execute fetching of current sequence value
         sql = query;
         PreparedStatement qps = conn.prepareStatement(query);
         try
         {
            ResultSet rs = qps.executeQuery();
            if (!rs.next())
            {
               String err = "could not read sequence 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 sequence value", sqle);
            throw sqle;
         }
         finally
         {
            qps.close();
         }

         // increment sequence value
         sql = update;
         long sequence = result + 1;
         PreparedStatement ups = conn.prepareStatement(update);
         try
         {
            ups.setLong(1, sequence);
            ups.setLong(2, result);
            ups.executeUpdate();
         }
         catch (SQLException sqle)
         {
            log.error("could not update sequence value in: " + tableName, sqle);
            throw sqle;
         }
         finally
         {
            ups.close();
         }

         // commit transaction to ensure updated sequence is not rolled back
         tm.commit();

         // transform sequence to the desired type and return the value
         Number typedSequence = IdentifierGeneratorFactory.createNumber(sequence, returnClass);
         if (log.isDebugEnabled())
         {
            log.debug("generate() returned: " + typedSequence);
         }
         return typedSequence;
      }
      catch (SQLException sqle)
      {
         throw JDBCExceptionHelper.convert(session.getFactory().getSQLExceptionConverter(),
                                           sqle,
                                           "could not get or update next value",
                                           sql);
      }
      catch (Exception e)
      {
         try
         {
            tm.rollback();
            throw new HibernateException(e);
         }
         catch (SystemException e1)
         {
            throw new HibernateException(e1);
         }
      }
      finally
      {
         if (conn != null)
            try
            {
               conn.close();
            }
            catch (SQLException e)
            {
               // ignore exception
            }
         // switch back to surrounding transaction context
         if (surroundingTransaction != null)
         {
            try
            {
               tm.resume(surroundingTransaction);
               if (log.isDebugEnabled())
               {
                  log.debug("surrounding tx resumed");
               }
            }
            catch (Exception e)
            {
               throw new HibernateException(e);
            }
         }
      }
   
public java.lang.ObjectgeneratorKey()

      return tableName;
   
public java.lang.String[]sqlCreateStrings(org.hibernate.dialect.Dialect dialect)

      return new String[]{
         "create table " + tableName + " ( " + columnName + " " + dialect.getTypeName(Types.BIGINT) + " )",
         "insert into " + tableName + " values ( 0 )"
      };
   
public java.lang.String[]sqlDropStrings(org.hibernate.dialect.Dialect dialect)

      //return "drop table " + tableName + dialect.getCascadeConstraintsString();
      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()};