Update of /cvsroot/hibernate/Hibernate2/src/net/sf/hibernate/id In directory sc8-pr-cvs1:/tmp/cvs-serv16192/net/sf/hibernate/id Modified Files: Assigned.java IdentifierGenerator.java SequenceGenerator.java SequenceHiLoGenerator.java UUIDHexGenerator.java UUIDStringGenerator.java Added Files: Configurable.java CounterGenerator.java IdentifierGeneratorFactory.java IdentityGenerator.java TableGenerator.java TableHiLoGenerator.java Removed Files: HexGenerator.java HiLoHexGenerator.java LongGenerator.java Log Message: redesigned id generator package applied Mark Woon's patch for generated alias lengths minor refactoring of Transaction package --- NEW FILE: Configurable.java --- //$Id: Configurable.java,v 1.1 2003/01/09 12:24:50 oneovthafew Exp $ package net.sf.hibernate.id; import java.util.Properties; import net.sf.hibernate.MappingException; import net.sf.hibernate.dialect.Dialect; import net.sf.hibernate.type.Type; /** * An <tt>IdentifierGenerator</tt> that supports "configuration". */ public interface Configurable { /** * Configure this instance, given the value of parameters * specified by the user as <tt><param></tt> elements. * @param params param values, keyed by parameter name */ public void configure(Type type, Properties params, Dialect d) throws MappingException; } --- NEW FILE: CounterGenerator.java --- //$Id: CounterGenerator.java,v 1.1 2003/01/09 12:24:50 oneovthafew Exp $ package net.sf.hibernate.id; import java.io.Serializable; import net.sf.hibernate.engine.SessionImplementor; /** * <b>vm</b><br> * <br> * An <tt>IdentifierGenerator</tt> that returns a <tt>long</tt>, * constructed from the system time and a counter value. Not safe * for use in a cluster! */ public class CounterGenerator implements IdentifierGenerator { private static short counter = (short) 0; protected short getCount() { synchronized(CounterGenerator.class) { if (counter<0) counter=0; return counter++; } } public Serializable generate(SessionImplementor cache, Object obj) { return new Long( ( System.currentTimeMillis() << 16 ) + getCount() ); } public static void main( String[] args ) throws Exception { IdentifierGenerator gen = new CounterGenerator(); for ( int i=0; i<5; i++) { long result = ( (Long) gen.generate(null, null) ).longValue(); System.out.println( result + " (" + Long.toHexString(result) + ")" ); } } } --- NEW FILE: IdentifierGeneratorFactory.java --- //$Id: IdentifierGeneratorFactory.java,v 1.1 2003/01/09 12:24:50 oneovthafew Exp $ package net.sf.hibernate.id; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.Properties; import net.sf.hibernate.MappingException; import net.sf.hibernate.dialect.Dialect; import net.sf.hibernate.type.Type; import net.sf.hibernate.util.ReflectHelper; /** * */ public class IdentifierGeneratorFactory { // unhappy about this being public ... is there a better way? public static Number get(ResultSet rs, Class clazz) throws SQLException, IdentifierGenerationException { if ( clazz==Long.class ) { return new Long( rs.getLong(1) ); } else if ( clazz==Integer.class ) { return new Integer( rs.getInt(1) ); } else if ( clazz==Short.class ) { return new Short( rs.getShort(1) ); } else { throw new IdentifierGenerationException("this id generator generates long, integer, short"); } } private static final HashMap idgenerators = new HashMap(); static { idgenerators.put("uuid.hex", UUIDHexGenerator.class); idgenerators.put("uuid.string", UUIDStringGenerator.class); idgenerators.put("hilo", TableHiLoGenerator.class); idgenerators.put("assigned", Assigned.class); idgenerators.put("identity", IdentityGenerator.class); idgenerators.put("sequence", SequenceGenerator.class); idgenerators.put("seqhilo", SequenceHiLoGenerator.class); idgenerators.put("vm", CounterGenerator.class); } public static IdentifierGenerator create(String strategy, Type type, Properties params, Dialect dialect) throws MappingException { try { Class clazz = (Class) idgenerators.get(strategy); if ( "native".equals(strategy) ) { if ( dialect.supportsIdentityColumns() ) { clazz = IdentityGenerator.class; } else if ( dialect.supportsSequences() ) { clazz = SequenceGenerator.class; } else { clazz = TableHiLoGenerator.class; } } if (clazz==null) clazz = ReflectHelper.classForName(strategy); IdentifierGenerator idgen = (IdentifierGenerator) clazz.newInstance(); if (idgen instanceof Configurable) ( (Configurable) idgen).configure(type, params, dialect); return idgen; } catch (Exception e) { throw new MappingException("could not instantiate id generator", e); } } static Number createNumber(long value, Class clazz) throws IdentifierGenerationException { if ( clazz==Long.class ) { return new Long(value); } else if ( clazz==Integer.class ) { return new Integer( (int) value ); } else if ( clazz==Short.class ) { return new Short( (short) value ); } else { throw new IdentifierGenerationException("this id generator generates long, integer, short"); } } } --- NEW FILE: IdentityGenerator.java --- //$Id: IdentityGenerator.java,v 1.1 2003/01/09 12:24:50 oneovthafew Exp $ package net.sf.hibernate.id; import net.sf.hibernate.HibernateException; import net.sf.hibernate.engine.SessionImplementor; import java.io.Serializable; import java.sql.SQLException; /** * <b>identity</b><br> * <br> * Indicates to the <tt>Session</tt> that identity (ie. identity/autoincrement * column) key generation should be used. * */ public class IdentityGenerator implements IdentifierGenerator { public Serializable generate(SessionImplementor s, Object obj) throws SQLException, HibernateException { return null; } } --- NEW FILE: TableGenerator.java --- //$Id: TableGenerator.java,v 1.1 2003/01/09 12:24:50 oneovthafew Exp $ package net.sf.hibernate.id; import java.io.Serializable; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import net.sf.hibernate.HibernateException; import net.sf.hibernate.dialect.Dialect; import net.sf.hibernate.engine.SessionImplementor; import net.sf.hibernate.type.Type; import net.sf.hibernate.util.PropertiesHelper; /** * An <tt>IdentifierGenerator</tt> that uses a database * table to store the last generated value. It is not * intended that applications use this strategy directly. * However, it may be used to build other (efficient) * strategies. The returned type is <tt>Integer</tt>.<br> * <br> * The hi value MUST be fetched in a seperate transaction * to the <tt>Session</tt> transaction so the generator must * be able to obtain a new connection and commit it. Hence * this implementation may not be used when Hibernate is * fetching connections from an application server datasource * or when the user is supplying connections.<br> * <br> * The returned value is of type <tt>integer</tt>.<br> * <br> * Mapping parameters supported: table, column * * @see TableHiLoGenerator */ public class TableGenerator implements PersistentIdentifierGenerator, Configurable { /** * The column parameter */ public static final String COLUMN = "column"; /** * The table parameter */ public static final String TABLE = "table"; private static final Log log = LogFactory.getLog(TableGenerator.class); private String tableName; private String columnName; private String query; private String update; public void configure(Type type, Properties params, Dialect dialect) { this.tableName = PropertiesHelper.getString(TABLE, params, "hibernate_unique_key"); this.columnName = PropertiesHelper.getString(COLUMN, params, "next_hi"); query = "select " + columnName + " from " + tableName; if ( dialect.supportsForUpdate() ) query += " for update"; update = "update " + tableName + " set " + columnName + " = ? where " + columnName + " = ?"; } public synchronized Serializable generate(SessionImplementor session, Object object) throws SQLException, HibernateException { // This has to be done using a different connection to the // containing transaction because the new hi value must // remain valid even if the containing transaction rolls // back Connection conn = session.getFactory().openConnection(); int result; int rows; try { do { // The loop ensures atomicity of the // select + update even for no transaction // or read committed isolation level PreparedStatement qps = conn.prepareStatement(query); 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.getInt(1); rs.close(); } catch (SQLException sqle) { log.error("could not read a hi value", sqle); throw sqle; } finally { qps.close(); } PreparedStatement ups = conn.prepareStatement(update); try { ups.setInt( 1, result + 1 ); ups.setInt( 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); conn.commit(); return new Integer(result); } finally { session.getFactory().closeConnection(conn); } } public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { return new String[] { "create table " + tableName + " ( " + columnName + " " + dialect.getTypeName(Types.INTEGER) + " )", "insert into " + tableName + " values ( 0 )" }; } public String sqlDropString(Dialect dialect) { return "drop table " + tableName; } public Object generatorKey() { return tableName; } } --- NEW FILE: TableHiLoGenerator.java --- //$Id: TableHiLoGenerator.java,v 1.1 2003/01/09 12:24:50 oneovthafew Exp $ package net.sf.hibernate.id; import java.io.Serializable; import java.sql.*; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import net.sf.hibernate.HibernateException; import net.sf.hibernate.dialect.Dialect; import net.sf.hibernate.engine.SessionImplementor; import net.sf.hibernate.type.Type; import net.sf.hibernate.util.PropertiesHelper; /** * <b>hilo</b><br> * <br> * An <tt>IdentifierGenerator</tt> that returns a <tt>Long</tt>, constructed using * a hi/lo algorithm. The hi value MUST be fetched in a seperate transaction * to the <tt>Session</tt> transaction so the generator must be able to obtain * a new connection and commit it. Hence this implementation may not * be used when Hibernate is fetching connections from an application * server datasource or when the user is supplying connections. In these * cases a <tt>SequenceHiLoGenerator</tt> would be a better choice (where * supported).<br> * <br> * Mapping parameters supported: table, column, max_lo * * @see SequenceHiLoGenerator */ public class TableHiLoGenerator extends TableGenerator { /** * The max_lo parameter */ public static final String MAX_LO = "max_lo"; private long hi; private int lo; private int maxLo; private Class returnClass; private static final Log log = LogFactory.getLog(TableHiLoGenerator.class); public void configure(Type type, Properties params, Dialect d) { super.configure(type, params, d); lo = maxLo = PropertiesHelper.getInt(MAX_LO, params, Short.MAX_VALUE); returnClass = type.returnedClass(); } public synchronized Serializable generate(SessionImplementor session, Object obj) throws SQLException, HibernateException { if (lo==maxLo) { int hival = ( (Integer) super.generate(session, obj) ).intValue(); lo = 0; hi = hival * (maxLo+1); log.debug("new hi value: " + hival); } return IdentifierGeneratorFactory.createNumber( hi + lo++, returnClass ); } } Index: Assigned.java =================================================================== RCS file: /cvsroot/hibernate/Hibernate2/src/net/sf/hibernate/id/Assigned.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Assigned.java 5 Jan 2003 02:11:21 -0000 1.3 --- Assigned.java 9 Jan 2003 12:24:50 -0000 1.4 *************** *** 28,32 **** return id; } - } --- 28,31 ---- Index: IdentifierGenerator.java =================================================================== RCS file: /cvsroot/hibernate/Hibernate2/src/net/sf/hibernate/id/IdentifierGenerator.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** IdentifierGenerator.java 5 Jan 2003 02:11:21 -0000 1.3 --- IdentifierGenerator.java 9 Jan 2003 12:24:50 -0000 1.4 *************** *** 25,28 **** --- 25,29 ---- */ public interface IdentifierGenerator { + /** * Generate a new identifier. *************** *** 34,37 **** --- 35,39 ---- */ public Serializable generate(SessionImplementor session, Object object) throws SQLException, HibernateException; + } Index: SequenceGenerator.java =================================================================== RCS file: /cvsroot/hibernate/Hibernate2/src/net/sf/hibernate/id/SequenceGenerator.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** SequenceGenerator.java 5 Jan 2003 02:11:21 -0000 1.3 --- SequenceGenerator.java 9 Jan 2003 12:24:50 -0000 1.4 *************** *** 3,7 **** import java.io.Serializable; ! import java.sql.*; import org.apache.commons.logging.Log; --- 3,10 ---- import java.io.Serializable; ! import java.sql.PreparedStatement; ! import java.sql.ResultSet; ! import java.sql.SQLException; ! import java.util.Properties; import org.apache.commons.logging.Log; *************** *** 9,14 **** --- 12,20 ---- import net.sf.hibernate.HibernateException; + import net.sf.hibernate.MappingException; import net.sf.hibernate.engine.SessionImplementor; + import net.sf.hibernate.type.Type; import net.sf.hibernate.util.JDBCExceptionReporter; + import net.sf.hibernate.util.PropertiesHelper; import net.sf.hibernate.dialect.Dialect; *************** *** 19,52 **** * performance algorithm is <tt>SequenceHiLoGenerator</tt>.<br> * <br> ! * One mapping parameter is supported: sequencename. * * @see SequenceHiLoGenerator ! * @see HiLoGenerator */ ! public class SequenceGenerator implements PersistentIdentifierGenerator { ! private final String sequenceName; ! private static final Log log = LogFactory.getLog(SequenceGenerator.class); ! public SequenceGenerator(String sequenceName) { ! this.sequenceName = sequenceName; ! } ! public SequenceGenerator() { ! this("hibernate_sequence"); } public Serializable generate(SessionImplementor session, Object obj) throws SQLException, HibernateException { - String sql = session.getFactory().getDialect().getSequenceNextValString(sequenceName); PreparedStatement st = session.getBatcher().prepareStatement(sql); try { ResultSet rs = st.executeQuery(); ! final Long result; try { rs.next(); ! result = new Long( rs.getLong(1) ); } finally { --- 25,62 ---- * performance algorithm is <tt>SequenceHiLoGenerator</tt>.<br> * <br> ! * One mapping parameter is supported: sequence. * * @see SequenceHiLoGenerator ! * @see TableHiLoGenerator */ ! public class SequenceGenerator implements PersistentIdentifierGenerator, Configurable { ! /** ! * The sequence parameter ! */ ! public static final String SEQUENCE = "sequence"; ! private String sequenceName; ! private Class returnClass; ! private String sql; ! private static final Log log = LogFactory.getLog(SequenceGenerator.class); ! public void configure(Type type, Properties params, Dialect dialect) throws MappingException { ! this.sequenceName = PropertiesHelper.getString(SEQUENCE, params, "hibernate_sequence"); ! returnClass = type.returnedClass(); ! sql = dialect.getSequenceNextValString(sequenceName); } public Serializable generate(SessionImplementor session, Object obj) throws SQLException, HibernateException { PreparedStatement st = session.getBatcher().prepareStatement(sql); try { ResultSet rs = st.executeQuery(); ! final Number result; try { rs.next(); ! result = IdentifierGeneratorFactory.get(rs, returnClass); } finally { Index: SequenceHiLoGenerator.java =================================================================== RCS file: /cvsroot/hibernate/Hibernate2/src/net/sf/hibernate/id/SequenceHiLoGenerator.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** SequenceHiLoGenerator.java 5 Jan 2003 02:11:21 -0000 1.3 --- SequenceHiLoGenerator.java 9 Jan 2003 12:24:50 -0000 1.4 *************** *** 4,7 **** --- 4,8 ---- import java.io.Serializable; import java.sql.SQLException; + import java.util.Properties; import org.apache.commons.logging.Log; *************** *** 9,16 **** import net.sf.hibernate.HibernateException; import net.sf.hibernate.engine.SessionImplementor; /** ! * <b>seqhilo.long</b><br> * <br> * An <tt>IdentifierGenerator</tt> that combines a hi/lo algorithm with an underlying --- 10,21 ---- import net.sf.hibernate.HibernateException; + import net.sf.hibernate.MappingException; + import net.sf.hibernate.dialect.Dialect; import net.sf.hibernate.engine.SessionImplementor; + import net.sf.hibernate.type.Type; + import net.sf.hibernate.util.PropertiesHelper; /** ! * <b>seqhilo</b><br> * <br> * An <tt>IdentifierGenerator</tt> that combines a hi/lo algorithm with an underlying *************** *** 18,56 **** * maximum lo value to determine how often new hi values are fetched.<br> * <br> ! * If sequences are not available, <tt>HiLoGenerator</tt> might be an * alternative.<br> * <br> ! * One mapping parameter is supported: sequencename. * ! * @see HiLoGenerator */ public class SequenceHiLoGenerator extends SequenceGenerator { private static final Log log = LogFactory.getLog(SequenceHiLoGenerator.class); ! private final int maxLoValue; private int lo; private long hi; ! public SequenceHiLoGenerator(String sequenceName, String maxLo) { ! super(sequenceName); ! lo = maxLoValue = Integer.parseInt(maxLo); ! } ! public SequenceHiLoGenerator(String sequenceName) { ! super(sequenceName); ! lo = maxLoValue = 9; ! } ! public SequenceHiLoGenerator() { ! this("hibernate_sequence"); } public synchronized Serializable generate(SessionImplementor session, Object obj) throws SQLException, HibernateException { if ( lo==maxLoValue ) { ! long hival = ( (Long) super.generate(session, obj) ).longValue(); ! log.debug("new hi value: " + hival); ! hi = hival * ( maxLoValue+1 ); lo = 0; } ! return new Long( hi + lo++ ); } --- 23,60 ---- * maximum lo value to determine how often new hi values are fetched.<br> * <br> ! * If sequences are not available, <tt>TableHiLoGenerator</tt> might be an * alternative.<br> * <br> ! * Mapping parameters supported: sequence, max_lo. * ! * @see TableHiLoGenerator */ public class SequenceHiLoGenerator extends SequenceGenerator { + public static final String SEQUENCE = "sequence"; + private static final Log log = LogFactory.getLog(SequenceHiLoGenerator.class); ! private int maxLoValue; private int lo; private long hi; + private Class returnClass; ! public void configure(Type type, Properties params, Dialect d) throws MappingException { ! super.configure(type, params, d); ! lo = maxLoValue = PropertiesHelper.getInt(SEQUENCE, params, 9); ! returnClass = type.returnedClass(); } public synchronized Serializable generate(SessionImplementor session, Object obj) throws SQLException, HibernateException { + if ( lo==maxLoValue ) { ! long hival = ( (Number) super.generate(session, obj) ).longValue(); lo = 0; + hi = hival * ( maxLoValue+1 ); + log.debug("new hi value: " + hival); } ! ! return IdentifierGeneratorFactory.createNumber( hi + lo++, returnClass ); } Index: UUIDHexGenerator.java =================================================================== RCS file: /cvsroot/hibernate/Hibernate2/src/net/sf/hibernate/id/UUIDHexGenerator.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** UUIDHexGenerator.java 5 Jan 2003 02:11:21 -0000 1.3 --- UUIDHexGenerator.java 9 Jan 2003 12:24:50 -0000 1.4 *************** *** 3,8 **** --- 3,13 ---- import java.io.Serializable; + import java.util.Properties; + import net.sf.hibernate.Hibernate; + import net.sf.hibernate.dialect.Dialect; import net.sf.hibernate.engine.SessionImplementor; + import net.sf.hibernate.type.Type; + import net.sf.hibernate.util.PropertiesHelper; /** *************** *** 10,33 **** * <br> * A <tt>UUIDGenerator</tt> that returns a string of length 32, ! * This string will consist of only hex digits. ! * Optionally, the string may be generated with seperators ! * between each component of the UUID. * * @see UUIDStringGenerator */ ! public class UUIDHexGenerator extends UUIDGenerator { ! ! private final String sep; ! ! public UUIDHexGenerator() { ! super(); ! sep = ""; ! } ! public UUIDHexGenerator(String sep) { ! super(); ! this.sep=sep; ! } protected String format(int intval) { --- 15,28 ---- * <br> * A <tt>UUIDGenerator</tt> that returns a string of length 32, ! * This string will consist of only hex digits. Optionally, ! * the string may be generated with seperators between each ! * component of the UUID. * * @see UUIDStringGenerator */ ! public class UUIDHexGenerator extends UUIDGenerator implements Configurable { ! private String sep; protected String format(int intval) { *************** *** 56,61 **** public static void main( String[] args ) throws Exception { ! IdentifierGenerator gen = new UUIDHexGenerator("/"); ! IdentifierGenerator gen2 = new UUIDHexGenerator("/"); for ( int i=0; i<10; i++) { String id = (String) gen.generate(null, null); --- 51,61 ---- public static void main( String[] args ) throws Exception { ! Properties props = new Properties(); ! props.setProperty("seperator", "/"); ! IdentifierGenerator gen = new UUIDHexGenerator(); ! ( (Configurable) gen ).configure(Hibernate.STRING, props, null); ! IdentifierGenerator gen2 = new UUIDHexGenerator(); ! ( (Configurable) gen2 ).configure(Hibernate.STRING, props, null); ! for ( int i=0; i<10; i++) { String id = (String) gen.generate(null, null); *************** *** 67,70 **** --- 67,74 ---- + public void configure(Type type, Properties params, Dialect d) { + sep = PropertiesHelper.getString("seperator", params, ""); + } + } Index: UUIDStringGenerator.java =================================================================== RCS file: /cvsroot/hibernate/Hibernate2/src/net/sf/hibernate/id/UUIDStringGenerator.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** UUIDStringGenerator.java 5 Jan 2003 02:11:21 -0000 1.3 --- UUIDStringGenerator.java 9 Jan 2003 12:24:50 -0000 1.4 *************** *** 5,9 **** import net.sf.hibernate.engine.SessionImplementor; ! import net.sf.hibernate.util.*; /** --- 5,9 ---- import net.sf.hibernate.engine.SessionImplementor; ! import net.sf.hibernate.util.BytesHelper; /** *************** *** 25,38 **** private String sep; - public UUIDStringGenerator() { - super(); - sep=""; - } - - public UUIDStringGenerator(String sep) { - super(); - this.sep=sep; - } - public Serializable generate(SessionImplementor cache, Object obj) { return new StringBuffer(20) --- 25,28 ---- *************** *** 46,50 **** public static void main( String[] args ) throws Exception { ! IdentifierGenerator gen = new UUIDStringGenerator();//("/"); for ( int i=0; i<5; i++) { String id = (String) gen.generate(null, null); --- 36,40 ---- public static void main( String[] args ) throws Exception { ! IdentifierGenerator gen = new UUIDStringGenerator(); for ( int i=0; i<5; i++) { String id = (String) gen.generate(null, null); *************** *** 60,64 **** return new String ( BytesHelper.toBytes(value) ); } ! } --- 50,54 ---- return new String ( BytesHelper.toBytes(value) ); } ! } --- HexGenerator.java DELETED --- --- HiLoHexGenerator.java DELETED --- --- LongGenerator.java DELETED --- |