db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From arm...@apache.org
Subject cvs commit: db-ojb/src/java/org/apache/ojb/broker/util/sequence SequenceManagerStoredProcedureImpl.java SequenceManagerHighLowImpl.java HighLowSequence.java AbstractSequenceManager.java SequenceManagerHelper.java SequenceManagerInMemoryImpl.java SequenceManagerMySQLImpl.java SequenceManagerNextValImpl.java SequenceManagerSeqHiLoImpl.java
Date Tue, 01 Apr 2003 14:09:41 GMT
arminw      2003/04/01 06:09:40

  Modified:    src/java/org/apache/ojb/broker/util/sequence
                        SequenceManagerHighLowImpl.java
                        HighLowSequence.java AbstractSequenceManager.java
                        SequenceManagerHelper.java
                        SequenceManagerInMemoryImpl.java
                        SequenceManagerMySQLImpl.java
                        SequenceManagerNextValImpl.java
                        SequenceManagerSeqHiLoImpl.java
  Added:       src/java/org/apache/ojb/broker/util/sequence
                        SequenceManagerStoredProcedureImpl.java
  Log:
  - update sequence package
  - add new SequenceManager implmentation
  use stored procedure to simulate an
  'oracle-like' sequence generation (Thanks Ryan)
  - sequence manager implementation
  now use long instead of int ids
  - SequenceManagerHighLowImpl now use optimistic
  locking
  
  Revision  Changes    Path
  1.16      +185 -48   db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerHighLowImpl.java
  
  Index: SequenceManagerHighLowImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerHighLowImpl.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- SequenceManagerHighLowImpl.java	8 Mar 2003 19:22:56 -0000	1.15
  +++ SequenceManagerHighLowImpl.java	1 Apr 2003 14:09:38 -0000	1.16
  @@ -56,7 +56,14 @@
   
   import org.apache.commons.lang.SystemUtils;
   import org.apache.ojb.broker.PersistenceBroker;
  +import org.apache.ojb.broker.PersistenceBrokerFactory;
  +import org.apache.ojb.broker.PersistenceBrokerException;
  +import org.apache.ojb.broker.OptimisticLockException;
  +import org.apache.ojb.broker.TransactionNotInProgressException;
   import org.apache.ojb.broker.metadata.FieldDescriptor;
  +import org.apache.ojb.broker.query.Criteria;
  +import org.apache.ojb.broker.query.Query;
  +import org.apache.ojb.broker.query.QueryByCriteria;
   import org.apache.ojb.broker.util.logging.Logger;
   import org.apache.ojb.broker.util.logging.LoggerFactory;
   
  @@ -66,12 +73,13 @@
   /**
    * High/Low sequence manager implementation generates unique and continuous
    * id's (during runtime) by using sequences to avoid database access.
  + * <br/>
    *
    * <p>
    * Implementation configuration properties:
    * </p>
    *
  - * <table align="left" cellspacing="2" cellpadding="2" border="1" frame="box" rules="all">
  + * <table cellspacing="2" cellpadding="2" border="3" frame="box">
    * <tr>
    *     <td><strong>Property Key</strong></td>
    *     <td><strong>Property Values</strong></td>
  @@ -89,17 +97,33 @@
    *     <td>globalSequenceId</td>
    *     <td>
    *         If set 'true' implementation use global unique
  - *         id's for all fields. This modus is NOT extent aware!
  - *         Default was 'false'.
  + *         id's for all fields. Default was 'false'.
  + *    </td>
  + * </tr>
  + * <tr>
  + *     <td>globalSequenceStart</td>
  + *     <td>
  + *         Set the start index of used global id
  + *         generation (e.g. set 100000, id generation starts with 100001)
    *    </td>
    * </tr>
    * </table>
    *
    * <br/>
  - * <br/>
  + * <p>
  + * <b>Limitations:</b>
  + * <ul>
  + *	<li>Do NOT use this implementation in j2ee environment or
  + * any comparable system where any connection was associated
  + * with the running tx.</li>
  + * </ul>
  + * </p>
  + *
  + *
    * <br/>
    * <br/>
    *
  + *
    * @see org.apache.ojb.broker.util.sequence.SequenceManager
    * @see org.apache.ojb.broker.util.sequence.SequenceManagerFactory
    * @see org.apache.ojb.broker.util.sequence.SequenceGenerator
  @@ -110,14 +134,21 @@
    */
   public class SequenceManagerHighLowImpl extends AbstractSequenceManager
   {
  -    private Logger log = LoggerFactory.getLogger(SequenceManagerHighLowImpl.class);
  -
  +    private static Logger log = LoggerFactory.getLogger(SequenceManagerHighLowImpl.class);
  +    /**
  +     * sequence name used for global id generation.
  +     */
  +    private static final String GLOBAL_SEQUENCE_NAME = "global - default sequence name";
       public static final String PROPERTY_GRAB_SIZE = "grabSize";
       public static final String PROPERTY_GLOBAL_SEQUENCE_ID = "globalSequenceId";
  +    public static final String PROPERTY_GLOBAL_SEQUENCE_START = "globalSequenceStart";
   
       private static Map sequencesMap = new HashMap();
  +
       protected boolean useGlobalSequenceIdentities;
       protected int grabSize;
  +    protected long globalSequenceStart;
  +    private int attempts;
   
       public SequenceManagerHighLowImpl(PersistenceBroker broker)
       {
  @@ -125,19 +156,17 @@
           grabSize = new Integer(getConfigurationProperty(PROPERTY_GRAB_SIZE, "20")).intValue();
           useGlobalSequenceIdentities =
                   new Boolean(getConfigurationProperty(PROPERTY_GLOBAL_SEQUENCE_ID, "false")).booleanValue();
  +        globalSequenceStart = new Long(
  +                getConfigurationProperty(PROPERTY_GLOBAL_SEQUENCE_START, "10000")).longValue();
       }
   
  -    /**
  -     * Gets a new uniqueId for the given Class and fieldname
  -     */
  -    protected int getUniqueId(FieldDescriptor field)
  -            throws SequenceManagerException
  +    protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException
       {
           HighLowSequence seq;
           String seqName;
           if (useGlobalSequenceIdentities)
           {
  -            seqName = SequenceManagerHelper.buildSequenceNameGlobal(getBrokerForClass(), field);
  +            seqName = GLOBAL_SEQUENCE_NAME;
           }
           else
           {
  @@ -154,59 +183,167 @@
           }
           synchronized (sequencesMap)
           {
  -            //try to found sequence in map
  +            // try to found sequence in map
               seq = (HighLowSequence) sequencesMap.get(seqName);
   
               if (seq == null)
               {
  -                // not found, create a new one and save it
  -                // get max id for class and extents from DB
  -                int lastId = SequenceManagerHelper.getMaxForExtent(getBrokerForClass(), field);
  -                //look up sequence
  -                seq = new HighLowSequence();
  -                seq.setTableName(seqName);
  -                seq.setFieldName(field.getColumnName());
  -                seq.setGrabSize(grabSize);
  -                seq.setMaxKey(lastId);
  -
  -                /* @todo we need a callback mechanism to notify
  -                sequence manager if a rollback was done, because
  -                the obtained sequence entry in DB was rollback too and we
  -                have to remove current HighLowSequence*/
  -
  -                seq = SequenceGenerator.getNextSequence(
  -                        getBrokerForClass(), seq);
  +                // not found, get sequence from database or create new
  +                seq = getSequence(getBrokerForClass(), field, seqName);
                   sequencesMap.put(seqName, seq);
               }
   
  -            //now we have a sequence
  -            int id = seq.getNextId();
  +            // now we have a sequence
  +            long id = seq.getNextId();
  +            // seq does not have reserved IDs => catch new block of keys
               if (id == 0)
               {
  -                /* @todo we need a callback mechanism to notify
  -                sequence manager if a rollback was done, because
  -                the obtained sequence entry in DB was rollback too and we
  -                have to remove current HighLowSequence*/
  -
  -                //seq does not have reserved IDs => reload seq
  -                seq = SequenceGenerator.getNextSequence(
  -                        getBrokerForClass(), seq);
  +                seq = getSequence(getBrokerForClass(), field, seqName);
                   // replace old sequence!!
                   sequencesMap.put(seqName, seq);
                   id = seq.getNextId();
  +                if (id == 0)
  +                {
  +                    // something going wrong
  +                    sequencesMap.remove(seqName);
  +                    throw new SequenceManagerException("Sequence generation failed: " +
  +                            SystemUtils.LINE_SEPARATOR + "Sequence: " + seq +
  +                            ". Unable to build new ID, id was always 0." +
  +                            SystemUtils.LINE_SEPARATOR + "Thread: " + Thread.currentThread() +
  +                            SystemUtils.LINE_SEPARATOR + "PB: " + getBrokerForClass());
  +                }
               }
  -            if (id == 0)
  +
  +            return id;
  +        }
  +    }
  +
  +    private HighLowSequence getSequence(PersistenceBroker brokerForSequence,
  +                                        FieldDescriptor field,
  +                                        String sequenceName)
  +    {
  +        HighLowSequence newSequence = null;
  +        PersistenceBroker internBroker = null;
  +        try
  +        {
  +            Criteria c = new Criteria();
  +            c.addLike("tableName", sequenceName);
  +            if (useGlobalSequenceIdentities)
               {
  -                throw new SequenceManagerException("Sequence generation failed: " +
  -                        SystemUtils.LINE_SEPARATOR + "Sequence: " + seq +
  -                        ". Unable to build new ID, id was always 0." +
  -                        SystemUtils.LINE_SEPARATOR + "Thread: " + Thread.currentThread() +
  -                        SystemUtils.LINE_SEPARATOR + "PB: " + getBrokerForClass());
  +                c.addLike("fieldName", PROPERTY_GLOBAL_SEQUENCE_ID);
               }
               else
               {
  -                return id;
  +                c.addLike("fieldName", field.getColumnName());
  +            }
  +            Query q = new QueryByCriteria(HighLowSequence.class, c);
  +
  +            /*
  +            arminw:
  +            we use a new internBroker instance, because we run into problems
  +            when current internBroker was rollback, then we have new sequence
  +            in memory, but not in database and a concurrent thread will
  +            get the same sequence.
  +            Thus we use a new internBroker instance (with new connection) to
  +            avoid this problem.
  +            */
  +            internBroker = PersistenceBrokerFactory.createPersistenceBroker(brokerForSequence.getPBKey());
  +            internBroker.beginTransaction();
  +            // first we lookup sequence object in database
  +            newSequence = (HighLowSequence) internBroker.getObjectByQuery(q);
  +
  +            //not in db --> we have to store a new sequence
  +            if (newSequence == null)
  +            {
  +                if (log.isDebugEnabled())
  +                {
  +                    log.debug("sequence for field " + field + " not found in db, store new HighLowSequence");
  +                }
  +                /*
  +                here we lookup the max key for the given field in system
  +                */
  +                long maxKey = getMaxKeyForSequence(brokerForSequence, field);
  +                newSequence = newSequenceObject(sequenceName, field);
  +                newSequence.setMaxKey(maxKey);
  +            }
  +            //set current grab size
  +            newSequence.setGrabSize(grabSize);
  +            //use copy to avoid sync problems!!
  +            // newSequence = newSequence.getCopy();
  +
  +            //grab the next key scope
  +            newSequence.grabNextKeySet();
  +
  +            //store the sequence to db
  +            try
  +            {
  +                /*
  +                arminw:
  +                remove object from cache to avoid problems when same
  +                objects where used with different databases. Currently
  +                (rc1) Identity does not differnce between databases, thus
  +                we could found an object in cache although it is not
  +                in the second database, it was used in the first database.
  +                If we not remove it PB try to update instead of insert.
  +                */
  +                internBroker.removeFromCache(newSequence);
  +                internBroker.store(newSequence);
  +            }
  +            catch (OptimisticLockException e)
  +            {
  +                // we try five times to get a new sequence
  +                if(attempts < 5)
  +                {
  +                    log.info("OptimisticLockException was thrown, will try again to store sequence. Sequence was "+newSequence);
  +                    attempts++;
  +                    getSequence(brokerForSequence, field, sequenceName);
  +                }
  +                else throw e;
               }
  +            internBroker.commitTransaction();
  +
  +            if (log.isDebugEnabled()) log.debug("new sequence was " + newSequence);
  +        }
  +        finally
  +        {
  +            attempts = 0;
  +            if (internBroker != null) internBroker.close();
  +        }
  +        return newSequence;
  +    }
  +
  +    private HighLowSequence newSequenceObject(String sequenceName,
  +                                              FieldDescriptor field)
  +    {
  +        HighLowSequence seq = new HighLowSequence();
  +        seq.setTableName(sequenceName);
  +        if (useGlobalSequenceIdentities)
  +        {
  +            seq.setFieldName(PROPERTY_GLOBAL_SEQUENCE_ID);
  +        }
  +        else
  +        {
  +            seq.setFieldName(field.getColumnName());
  +        }
  +        seq.setGrabSize(grabSize);
  +        return seq;
  +    }
  +
  +    private long getMaxKeyForSequence(PersistenceBroker broker,
  +                                        FieldDescriptor field)
  +    {
  +        long maxKey = 0;
  +        if (useGlobalSequenceIdentities)
  +        {
  +            maxKey = globalSequenceStart;
  +        }
  +        else
  +        {
  +            /*
  +            here we lookup the max key for the given field in system
  +            */
  +            maxKey = SequenceManagerHelper.getMaxForExtent(broker, field);
           }
  +        return maxKey;
       }
   }
  
  
  
  1.4       +36 -26    db-ojb/src/java/org/apache/ojb/broker/util/sequence/HighLowSequence.java
  
  Index: HighLowSequence.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/sequence/HighLowSequence.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- HighLowSequence.java	9 Aug 2002 10:49:20 -0000	1.3
  +++ HighLowSequence.java	1 Apr 2003 14:09:38 -0000	1.4
  @@ -1,5 +1,10 @@
   package org.apache.ojb.broker.util.sequence;
   
  +import org.apache.commons.lang.builder.ToStringBuilder;
  +import org.apache.commons.lang.builder.ToStringStyle;
  +
  +import java.io.Serializable;
  +
   /* ====================================================================
    * The Apache Software License, Version 1.1
    *
  @@ -56,23 +61,22 @@
   
   
   /**
  - * The HighLowSequence is the persistent part of the HighLowSequenceGenerator.
  - * It makes the maximum reserved key persistently availabe.
  + * The HighLowSequence is the persistent part of the {@link SequenceManagerHighLowImpl}.
  + * It makes the maximum reserved key persistently available.
    *
    * @author    R Bischof
    * @created   26. Oktober 2001
  + * @version $Id$
    */
  -public class HighLowSequence
  +public class HighLowSequence implements Serializable
   {
       private String tableName;
       private String fieldName;
  -    private int maxKey;
  +    private long maxKey;
       private int grabSize;
  -    /**
  -     * This is not stored in the DB
  -     */
  -    private int curVal = 0;
  -
  +    private int version;
  +     // This is not stored in the DB
  +    private long curVal = 0;
   
       /**
        * Default constructor for the HighLowSequence object
  @@ -81,16 +85,15 @@
       {
       }
   
  -
       /**
        * Constructor for the HighLowSequence object
        *
  -     * @param tableName  The classname of this sequence
  +     * @param tableName  The name of the sequence
        * @param fieldName  The fieldname of this sequence
        * @param maxKey     The maximum key currently in use
        * @param grabSize   The grab size, i.e. the number of keys to reserve
        */
  -    public HighLowSequence(String tableName, String fieldName, int maxKey, int grabSize)
  +    public HighLowSequence(String tableName, String fieldName, long maxKey, int grabSize)
       {
           this.tableName = tableName;
           this.fieldName = fieldName;
  @@ -105,8 +108,24 @@
   
       public String toString()
       {
  -        return "[sequence: tableName=" + tableName + " fieldName=" + fieldName + " currentKey=" +
  -                curVal + " maxKey=" + maxKey + " grabSize=" + grabSize + " " + super.toString() + "]";
  +        ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE);
  +        buf.append("tableName", tableName).
  +                append("fieldName", fieldName).
  +                append("grabSize", grabSize).
  +                append("version", version).
  +                append("maxKey", maxKey).
  +                append("currentKey", curVal);
  +        return buf.toString();
  +    }
  +
  +    public int getVersion()
  +    {
  +        return version;
  +    }
  +
  +    public void setVersion(int version)
  +    {
  +        this.version = version;
       }
   
       /**
  @@ -119,7 +138,6 @@
           this.tableName = tableName;
       }
   
  -
       /**
        * Sets the grab size attribute of the HighLowSequence object
        *
  @@ -130,7 +148,6 @@
           this.grabSize = grabSize;
       }
   
  -
       /**
        * Sets the fieldName attribute of the HighLowSequence object
        *
  @@ -141,18 +158,16 @@
           this.fieldName = fieldName;
       }
   
  -
       /**
        * Sets the maxKey attribute of the HighLowSequence object
        *
        * @param maxKey  The new maxKey value
        */
  -    public void setMaxKey(int maxKey)
  +    public void setMaxKey(long maxKey)
       {
           this.maxKey = maxKey;
       }
   
  -
       /**
        * Gets the className attribute of the HighLowSequence object
        *
  @@ -163,7 +178,6 @@
           return this.tableName;
       }
   
  -
       /**
        * Gets the grabSize attribute of the HighLowSequence object
        *
  @@ -174,7 +188,6 @@
           return this.grabSize;
       }
   
  -
       /**
        * Gets the fieldName attribute of the HighLowSequence object
        *
  @@ -185,13 +198,12 @@
           return this.fieldName;
       }
   
  -
       /**
        * Gets the next key from this sequence
        *
        * @return   The next key or 0 if sequence needs to grab new keyset
        */
  -    public int getNextId()
  +    public long getNextId()
       {
           if (curVal == maxKey)
           {
  @@ -205,17 +217,15 @@
           }
       }
   
  -
       /**
        * Gets the maxKey attribute of the HighLowSequence object
        *
        * @return   The maxKey value
        */
  -    public int getMaxKey()
  +    public long getMaxKey()
       {
           return this.maxKey;
       }
  -
   
       /**
        * Grabs the next key set, the sequence must be saved afterwards!!
  
  
  
  1.7       +150 -150  db-ojb/src/java/org/apache/ojb/broker/util/sequence/AbstractSequenceManager.java
  
  Index: AbstractSequenceManager.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/sequence/AbstractSequenceManager.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- AbstractSequenceManager.java	8 Mar 2003 19:22:56 -0000	1.6
  +++ AbstractSequenceManager.java	1 Apr 2003 14:09:39 -0000	1.7
  @@ -1,12 +1,5 @@
   package org.apache.ojb.broker.util.sequence;
   
  -import java.math.BigDecimal;
  -import java.sql.Date;
  -import java.sql.Time;
  -import java.sql.Timestamp;
  -import java.sql.Types;
  -import java.util.Properties;
  -
   import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.broker.accesslayer.JdbcAccess;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
  @@ -16,6 +9,13 @@
   import org.apache.ojb.broker.util.logging.Logger;
   import org.apache.ojb.broker.util.logging.LoggerFactory;
   
  +import java.math.BigDecimal;
  +import java.sql.Date;
  +import java.sql.Time;
  +import java.sql.Timestamp;
  +import java.sql.Types;
  +import java.util.Properties;
  +
   
   /**
    * A base class for sequence manager implementations.
  @@ -58,6 +58,13 @@
           }
       }
   
  +    /**
  +     * returns a unique long value for field.
  +     * the returned number is unique accross all tables in the extent of clazz.
  +     */
  +    abstract protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException;
  +
  +
       public Platform getPlatform()
       {
           return platform;
  @@ -92,7 +99,7 @@
   
       //****************************************************************
       // method implementations of SequenceManager interface
  -    //****************************************************************  
  +    //****************************************************************
       /**
        * Returns a unique object for the given field attribute.
        * The returned value takes in account the jdbc-type
  @@ -102,161 +109,138 @@
        */
       public Object getUniqueValue(FieldDescriptor field) throws SequenceManagerException
       {
  -    	Object result = null;
  -    	switch (field.getColumnJdbcType())
  -    	{
  -    		case Types.ARRAY:
  -    		{
  -    			Object[] arr = {getUniqueString(field)};
  -    			result = arr;
  -    			break;
  -    		}	
  -    		case Types.BIGINT:
  -    		{
  -    			result = new Long(getUniqueLong(field));
  -    			break;
  -    		}	
  -    		case Types.BINARY:
  -    		{
  -    			result = (byte[]) getUniqueString(field).getBytes();
  -    			break;
  -    		}	
  -    		case Types.CHAR:
  -    		{
  -    			result = getUniqueString(field);
  -    			break;
  -    		}	
  -    		case Types.DATE:
  -    		{
  -    			result = new Date(getUniqueLong(field));
  -    			break;
  -    		}	
  -    		case Types.DECIMAL:
  -    		{
  -    			result = new BigDecimal(getUniqueLong(field));
  -    			break;
  -    		}	
  -    		case Types.DOUBLE:
  -    		{
  -    			result = new Double(getUniqueLong(field));
  -    			break;
  -    		}	
  -    		case Types.FLOAT:
  -    		{
  -    			result = new Double(getUniqueLong(field));
  -    			break;
  -    		}	
  -    		case Types.INTEGER:
  -    		{
  -    			result = new Integer(getUniqueId(field));
  -    			break;
  -    		}	
  -    		case Types.JAVA_OBJECT:
  -    		{
  -    			result = getUniqueObject(field);
  -    			break;
  -    		}	
  -    		case Types.LONGVARBINARY:
  -    		{
  -    			result = (byte[]) getUniqueString(field).getBytes();
  -    			break;
  -    		}	
  -    		case Types.LONGVARCHAR:
  -    		{
  -    			result = getUniqueString(field);
  -    			break;
  -    		}	
  -    		case Types.NUMERIC:
  -    		{
  -    			result = new BigDecimal(getUniqueLong(field));
  -    			break;
  -    		}	
  -    		case Types.REAL:
  -    		{
  -    			result = new Float(getUniqueLong(field));
  -    			break;
  -    		}	
  -    		case Types.SMALLINT:
  -    		{
  -    			result = new Short((short)getUniqueId(field));
  -    			break;
  -    		}	
  -    		case Types.TIME:
  -    		{
  -    			result = new Time(getUniqueLong(field));
  -    			break;
  -    		}	
  -    		case Types.TIMESTAMP:
  -    		{
  -    			result = new Timestamp(getUniqueLong(field));
  -    			break;
  -    		}	
  -    		case Types.TINYINT:
  -    		{
  -    			result = new Byte((byte)getUniqueId(field));
  -    			break;
  -    		}	
  -    		case Types.VARBINARY:
  -    		{
  -    			result = (byte[]) getUniqueString(field).getBytes();
  -    			break;
  -    		}	
  -    		case Types.VARCHAR:
  -    		{
  -    			result = getUniqueString(field);
  -    			break;
  -    		}
  -    		default:
  -    		{
  -    			result = getUniqueString(field);
  -    			break;	
  -    		}
  -    	}
  -    	// perform a sql to java conversion here, so that clients do
  -    	// not see any db specific values
  -    	result = field.getFieldConversion().sqlToJava(result);
  +        Object result = null;
  +        switch (field.getColumnJdbcType())
  +        {
  +            case Types.ARRAY:
  +                {
  +                    Object[] arr = {getUniqueString(field)};
  +                    result = arr;
  +                    break;
  +                }
  +            case Types.BIGINT:
  +                {
  +                    result = new Long(getUniqueLong(field));
  +                    break;
  +                }
  +            case Types.BINARY:
  +                {
  +                    result = (byte[]) getUniqueString(field).getBytes();
  +                    break;
  +                }
  +            case Types.CHAR:
  +                {
  +                    result = getUniqueString(field);
  +                    break;
  +                }
  +            case Types.DATE:
  +                {
  +                    result = new Date(getUniqueLong(field));
  +                    break;
  +                }
  +            case Types.DECIMAL:
  +                {
  +                    result = new BigDecimal(getUniqueLong(field));
  +                    break;
  +                }
  +            case Types.DOUBLE:
  +                {
  +                    result = new Double(getUniqueLong(field));
  +                    break;
  +                }
  +            case Types.FLOAT:
  +                {
  +                    result = new Double(getUniqueLong(field));
  +                    break;
  +                }
  +            case Types.INTEGER:
  +                {
  +                    result = new Integer(getUniqueId(field));
  +                    break;
  +                }
  +            case Types.JAVA_OBJECT:
  +                {
  +                    result = getUniqueObject(field);
  +                    break;
  +                }
  +            case Types.LONGVARBINARY:
  +                {
  +                    result = (byte[]) getUniqueString(field).getBytes();
  +                    break;
  +                }
  +            case Types.LONGVARCHAR:
  +                {
  +                    result = getUniqueString(field);
  +                    break;
  +                }
  +            case Types.NUMERIC:
  +                {
  +                    result = new BigDecimal(getUniqueLong(field));
  +                    break;
  +                }
  +            case Types.REAL:
  +                {
  +                    result = new Float(getUniqueLong(field));
  +                    break;
  +                }
  +            case Types.SMALLINT:
  +                {
  +                    result = new Short((short) getUniqueId(field));
  +                    break;
  +                }
  +            case Types.TIME:
  +                {
  +                    result = new Time(getUniqueLong(field));
  +                    break;
  +                }
  +            case Types.TIMESTAMP:
  +                {
  +                    result = new Timestamp(getUniqueLong(field));
  +                    break;
  +                }
  +            case Types.TINYINT:
  +                {
  +                    result = new Byte((byte) getUniqueId(field));
  +                    break;
  +                }
  +            case Types.VARBINARY:
  +                {
  +                    result = (byte[]) getUniqueString(field).getBytes();
  +                    break;
  +                }
  +            case Types.VARCHAR:
  +                {
  +                    result = getUniqueString(field);
  +                    break;
  +                }
  +            default:
  +                {
  +                    result = getUniqueString(field);
  +                    break;
  +                }
  +        }
  +        // perform a sql to java conversion here, so that clients do
  +        // not see any db specific values
  +        result = field.getFieldConversion().sqlToJava(result);
           return result;
  -    }    
  -
  -    /**
  -     * noop
  -     */
  -    public void afterStore(JdbcAccess dbAccess, ClassDescriptor cld, Object obj)
  -            throws SequenceManagerException
  -    {
       }
   
       /**
  -     * noop
  -     */
  -    public void setReferenceFKs(Object obj, ClassDescriptor cld)
  -            throws SequenceManagerException
  -    {
  -    }
  -    
  -    /**
  -     * returns a new unique int for the given Class and fieldname
  -     */
  -    abstract protected int getUniqueId(FieldDescriptor field)
  -            throws SequenceManagerException;
  -            
  -    /**
        * returns a unique String for class clazz and field fieldName.
        * the returned uid is unique accross all tables in the extent of clazz.
        *
        */
       protected String getUniqueString(FieldDescriptor field) throws SequenceManagerException
       {
  -        return Integer.toString(getUniqueId(field));
  +        return Long.toString(getUniqueLong(field));
       }
   
       /**
  -     * returns a unique long value for class clazz and field fieldName.
  -     * the returned number is unique accross all tables in the extent of clazz.
  +     * Returns a new unique int for the given Class and fieldname.
        */
  -    protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException
  +    protected int getUniqueId(FieldDescriptor field) throws SequenceManagerException
       {
  -        return (long) getUniqueId(field);
  +        return (int) getUniqueLong(field);
       }
   
       /**
  @@ -267,5 +251,21 @@
       {
           return getUniqueString(field);
       }
  -    
  +
  +    /**
  +     * noop
  +     */
  +    public void afterStore(JdbcAccess dbAccess, ClassDescriptor cld, Object obj)
  +            throws SequenceManagerException
  +    {
  +    }
  +
  +    /**
  +     * noop
  +     */
  +    public void setReferenceFKs(Object obj, ClassDescriptor cld)
  +            throws SequenceManagerException
  +    {
  +    }
   }
  +
  
  
  
  1.9       +27 -19    db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerHelper.java
  
  Index: SequenceManagerHelper.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerHelper.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- SequenceManagerHelper.java	12 Jan 2003 10:03:32 -0000	1.8
  +++ SequenceManagerHelper.java	1 Apr 2003 14:09:39 -0000	1.9
  @@ -30,7 +30,7 @@
       /**
        * Prefix for global sequence names.
        */
  -    private static final String GLOBAL_SEQUENCE_NAME = "global - ";
  +    //private static final String GLOBAL_SEQUENCE_NAME = "global - default sequence name";
   
       /**
        * Returns a unique sequence name (unique across all extents).
  @@ -75,6 +75,14 @@
            */
           if (cldTopLevel.isExtent())
           {
  +            /*
  +            TODO
  +            arminw:
  +            this is a little critical, because we do not know if the extent classes
  +            will change by and by and the first found extent class may change, thus the
  +            returned table name could change!
  +            But I don't know a way to resolve this problem. I put a comment to the docs
  +            */
               seqName = brokerForClass.getClassDescriptor(((Class) cldTopLevel.getExtentClasses().
                       get(0))).getFullTableName();
           }
  @@ -86,23 +94,23 @@
           return SEQ_PREFIX + seqName;
       }
   
  -    /**
  -     * Build a global sequence name unique across all tables.
  -     */
  -    public static String buildSequenceNameGlobal(PersistenceBroker brokerForClass, FieldDescriptor field)
  -    {
  -        return GLOBAL_SEQUENCE_NAME + (field != null ? field.getColumnName() : "defaultField");
  -    }
  +//    /**
  +//     * Build a global sequence name unique across all tables.
  +//     */
  +//    public static String buildSequenceNameGlobal()
  +//    {
  +//        return GLOBAL_SEQUENCE_NAME;
  +//    }
   
       /**
        * Lookup all tables associated with given class (search all extent classes)
        * to find the current maximum value for the given field.
  -     * <br><b>Note:</b> Only works for integer single autoincrement fields.
  +     * <br><b>Note:</b> Only works for <code>long</code> autoincrement fields.
        * @param brokerForClass persistence broker instance match the database of the
  -     * given class
  -     * @param clazz the target class
  +     * given field/class
  +     * @param field the target field
        */
  -    public static int getMaxForExtent(PersistenceBroker brokerForClass, FieldDescriptor field) throws PersistenceBrokerException
  +    public static long getMaxForExtent(PersistenceBroker brokerForClass, FieldDescriptor field) throws PersistenceBrokerException
       {
           if (field == null)
           {
  @@ -119,10 +127,10 @@
        * Search down all extent classes and return max of all found
        * PK values.
        */
  -    private static int getMaxId(PersistenceBroker brokerForClass, Class topLevel, FieldDescriptor original) throws PersistenceBrokerException
  +    private static long getMaxId(PersistenceBroker brokerForClass, Class topLevel, FieldDescriptor original) throws PersistenceBrokerException
       {
  -        int max = 0;
  -        int tmp = 0;
  +        long max = 0;
  +        long tmp = 0;
           ClassDescriptor cld = brokerForClass.getClassDescriptor(topLevel);
   
           // if class is no Interface we have to search its directly mapped table
  @@ -167,7 +175,7 @@
        * lookup current maximum value for a single field in
        * table the given class descriptor was associated.
        */
  -    private static int getMaxIdForClass(
  +    private static long getMaxIdForClass(
               PersistenceBroker brokerForClass, ClassDescriptor cldForOriginalOrExtent, FieldDescriptor original)
               throws PersistenceBrokerException
       {
  @@ -193,7 +201,7 @@
           }
   
           String column = field.getColumnName();
  -        int result = 0;
  +        long result = 0;
           ResultSet rs = null;
           Statement stmt = null;
           String table = cldForOriginalOrExtent.getFullTableName();
  @@ -205,7 +213,7 @@
               stmt = brokerForClass.serviceStatementManager().getGenericStatement(cldForOriginalOrExtent, Query.NOT_SCROLLABLE);
               rs = stmt.executeQuery(sql);
               rs.next();
  -            result = rs.getInt(1);
  +            result = rs.getLong(1);
           }
           catch (Exception e)
           {
  
  
  
  1.9       +14 -45    db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerInMemoryImpl.java
  
  Index: SequenceManagerInMemoryImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerInMemoryImpl.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- SequenceManagerInMemoryImpl.java	8 Mar 2003 19:22:56 -0000	1.8
  +++ SequenceManagerInMemoryImpl.java	1 Apr 2003 14:09:39 -0000	1.9
  @@ -68,35 +68,25 @@
    * </p>
    * <b>Limitations:</b>
    * <ul type="disc">
  - *	<li>do not use in client/server mode</li>
    *	<li>do not use in clustered environments</li>
  - *	<li>do not use if other entities generate id's for objects</li>
  + *	<li>do not use if other applications generate id's for objects</li>
    * </ul>
    *
  + *
  + *
    * <p>
    * Implementation configuration properties:
    * </p>
    *
  - * <table align="left" cellspacing="2" cellpadding="2" border="1" frame="box" rules="all">
  + * <table cellspacing="2" cellpadding="2" border="3" frame="box">
    * <tr>
    *     <td><strong>Property Key</strong></td>
    *     <td><strong>Property Values</strong></td>
    * </tr>
    * <tr>
  - *     <td>grabSize</td>
  + *     <td>none</td>
    *     <td>
  - *         Integer entry determines the
  - *         number of IDs allocated within the
  - *         H/L sequence manager implementation.
  - *         Default was '20'.
  - *    </td>
  - * </tr>
  - * <tr>
  - *     <td>globalSequenceId</td>
  - *     <td>
  - *         If set 'true' implementation use global unique
  - *         id's for all fields. This modus is NOT extent aware!
  - *         Default was 'false'.
  + *
    *    </td>
    * </tr>
    * </table>
  @@ -104,62 +94,41 @@
    * <br/>
    * <br/>
    * <br/>
  - * <br/>
  - * <br/>
  - * <br/>
  - * <br/>
    *
    * @see org.apache.ojb.broker.util.sequence.SequenceManager
    * @see org.apache.ojb.broker.util.sequence.SequenceManagerFactory
    * @see org.apache.ojb.broker.util.sequence.SequenceGenerator
    * @see org.apache.ojb.broker.util.sequence.SequenceManagerHelper
  - *
    * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
    * @version $Id$
    */
   public class SequenceManagerInMemoryImpl extends AbstractSequenceManager
   {
  -    public static final String PROPERTY_GLOBAL_SEQUENCE_ID = "globalSequenceId";
       private static HashMap sequenceNameKeyMap = new HashMap();
  -    protected boolean useGlobalSequenceIdentities;
   
       public SequenceManagerInMemoryImpl(PersistenceBroker broker)
       {
           super(broker);
  -        useGlobalSequenceIdentities =
  -                new Boolean(getConfigurationProperty(PROPERTY_GLOBAL_SEQUENCE_ID, "false")).booleanValue();
       }
   
  -    protected int getUniqueId(FieldDescriptor field) throws SequenceManagerException
  +    protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException
       {
  -        String seqName;
  -        int retId = 0;
  -        if (useGlobalSequenceIdentities)
  -        {
  -            seqName = SequenceManagerHelper.buildSequenceNameGlobal(getBrokerForClass(), field);
  -        }
  -        else
  -        {
  -            seqName = SequenceManagerHelper.buildSequenceName(getBrokerForClass(), field);
  -        }
  -
  +        String seqName = SequenceManagerHelper.buildSequenceName(getBrokerForClass(), field);
  +        // we have to be threadsafe
           synchronized (sequenceNameKeyMap)
           {
               // get id for given seq name
  -            Integer currentId = (Integer) sequenceNameKeyMap.get(seqName);
  +            Long currentId = (Long) sequenceNameKeyMap.get(seqName);
               // check - first time we search for sequence name
               if (currentId == null)
               {
  -                currentId = new Integer(
  +                currentId = new Long(
                           SequenceManagerHelper.getMaxForExtent(getBrokerForClass(), field));
  -                // check for start index
  -                currentId = new Integer(currentId.intValue());
               }
  -            retId = currentId.intValue() + 1;
  -            currentId = new Integer(retId);
  +            currentId = new Long(currentId.longValue() + 1);
               // put new id back to map
               sequenceNameKeyMap.put(seqName, currentId);
  +            return currentId.intValue();
           }
  -        return retId;
       }
   }
  
  
  
  1.11      +103 -43   db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerMySQLImpl.java
  
  Index: SequenceManagerMySQLImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerMySQLImpl.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- SequenceManagerMySQLImpl.java	8 Mar 2003 19:22:56 -0000	1.10
  +++ SequenceManagerMySQLImpl.java	1 Apr 2003 14:09:39 -0000	1.11
  @@ -1,17 +1,57 @@
  -/**
  +package org.apache.ojb.broker.util.sequence;
  +/* ====================================================================
  + * The Apache Software License, Version 1.1
    *
  - * MySQL SequenceManager for use with auto_increment columns.
  - * <p>
  - * WARNING: Not thoroughly tested, use at own risk.  ;-)
  + * Copyright (c) 2001 The Apache Software Foundation.  All rights
  + * reserved.
    *
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
    *
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
    *
  - * @author Travis Reeder - travis@spaceprogram.com
  - * @version $Id$
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in
  + *    the documentation and/or other materials provided with the
  + *    distribution.
  + *
  + * 3. The end-user documentation included with the redistribution,
  + *    if any, must include the following acknowledgment:
  + *       "This product includes software developed by the
  + *        Apache Software Foundation (http://www.apache.org/)."
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
    *
  + * 4. The names "Apache" and "Apache Software Foundation" and
  + *    "Apache ObjectRelationalBridge" must not be used to endorse or promote products
  + *    derived from this software without prior written permission. For
  + *    written permission, please contact apache@apache.org.
  + *
  + * 5. Products derived from this software may not be called "Apache",
  + *    "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
  + *    prior written permission of the Apache Software Foundation.
  + *
  + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + * ====================================================================
  + *
  + * This software consists of voluntary contributions made by many
  + * individuals on behalf of the Apache Software Foundation.  For more
  + * information on the Apache Software Foundation, please see
  + * <http://www.apache.org/>.
    */
  -package org.apache.ojb.broker.util.sequence;
  -
   import java.math.BigDecimal;
   import java.sql.Date;
   import java.sql.SQLException;
  @@ -21,8 +61,6 @@
   import java.util.Iterator;
   import java.util.Vector;
   
  -import org.apache.commons.logging.Log;
  -import org.apache.commons.logging.LogFactory;
   import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.broker.PersistenceBrokerException;
   import org.apache.ojb.broker.accesslayer.JdbcAccess;
  @@ -33,34 +71,58 @@
   import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
   import org.apache.ojb.broker.query.Query;
   import org.apache.ojb.broker.util.ProxyHelper;
  +import org.apache.ojb.broker.util.logging.Logger;
  +import org.apache.ojb.broker.util.logging.LoggerFactory;
   
  -
  +/**
  + * MySQL SequenceManager for use with auto_increment columns.
  + * <p>
  + * <b>WARNING:</b> Not thoroughly tested, use at own risk.  ;-)
  + * <br/>
  + * Native key generation is not extent aware if the extent persistent
  + * objects using different database tables.
  + *
  + * <p>
  + * Implementation configuration properties:
  + * </p>
  + *
  + * <table cellspacing="2" cellpadding="2" border="3" frame="box">
  + * <tr>
  + *     <td><strong>Property Key</strong></td>
  + *     <td><strong>Property Values</strong></td>
  + * </tr>
  + * <tr>
  + *     <td>none</td>
  + *     <td>
  + *
  + *    </td>
  + * </tr>
  + * </table>
  + * <br/>
  + * <br/>
  + *
  + * @author Travis Reeder - travis@spaceprogram.com
  + * @version $Id$
  + *
  + */
   public class SequenceManagerMySQLImpl implements SequenceManager
   {
  -
  -    private Log log = LogFactory.getLog(this.getClass());
  +    private Logger log = LoggerFactory.getLogger(SequenceManagerMySQLImpl.class);
   
       /**
        * reference to the PersistenceBroker
        */
       protected PersistenceBroker broker;
  -
       /**
        * singleton instance of the SequenceManager
        */
       private static SequenceManagerMySQLImpl _instance;
   
  -    /**
  -     *
  -     * Public constructor
  -     *
  -     */
       public SequenceManagerMySQLImpl(PersistenceBroker broker)
       {
           this.broker = broker;
       }
   
  -
       /**
        * Returns next Id get from "sequence sequence.NextVal from Dual".
        * Mount sequence name as:
  @@ -214,97 +276,97 @@
       			Object[] arr = {getUniqueString(field)};
       			result = arr;
       			break;
  -    		}	
  +    		}
       		case Types.BIGINT:
       		{
       			result = new Long(getUniqueLong(field));
       			break;
  -    		}	
  +    		}
       		case Types.BINARY:
       		{
       			result = (byte[]) getUniqueString(field).getBytes();
       			break;
  -    		}	
  +    		}
       		case Types.CHAR:
       		{
       			result = getUniqueString(field);
       			break;
  -    		}	
  +    		}
       		case Types.DATE:
       		{
       			result = new Date(getUniqueLong(field));
       			break;
  -    		}	
  +    		}
       		case Types.DECIMAL:
       		{
       			result = new BigDecimal(getUniqueLong(field));
       			break;
  -    		}	
  +    		}
       		case Types.DOUBLE:
       		{
       			result = new Double(getUniqueLong(field));
       			break;
  -    		}	
  +    		}
       		case Types.FLOAT:
       		{
       			result = new Double(getUniqueLong(field));
       			break;
  -    		}	
  +    		}
       		case Types.INTEGER:
       		{
       			result = new Integer(getUniqueId(field));
       			break;
  -    		}	
  +    		}
       		case Types.JAVA_OBJECT:
       		{
       			result = getUniqueObject(field);
       			break;
  -    		}	
  +    		}
       		case Types.LONGVARBINARY:
       		{
       			result = (byte[]) getUniqueString(field).getBytes();
       			break;
  -    		}	
  +    		}
       		case Types.LONGVARCHAR:
       		{
       			result = getUniqueString(field);
       			break;
  -    		}	
  +    		}
       		case Types.NUMERIC:
       		{
       			result = new BigDecimal(getUniqueLong(field));
       			break;
  -    		}	
  +    		}
       		case Types.REAL:
       		{
       			result = new Float(getUniqueLong(field));
       			break;
  -    		}	
  +    		}
       		case Types.SMALLINT:
       		{
       			result = new Short((short)getUniqueId(field));
       			break;
  -    		}	
  +    		}
       		case Types.TIME:
       		{
       			result = new Time(getUniqueLong(field));
       			break;
  -    		}	
  +    		}
       		case Types.TIMESTAMP:
       		{
       			result = new Timestamp(getUniqueLong(field));
       			break;
  -    		}	
  +    		}
       		case Types.TINYINT:
       		{
       			result = new Byte((byte)getUniqueId(field));
       			break;
  -    		}	
  +    		}
       		case Types.VARBINARY:
       		{
       			result = (byte[]) getUniqueString(field).getBytes();
       			break;
  -    		}	
  +    		}
       		case Types.VARCHAR:
       		{
       			result = getUniqueString(field);
  @@ -313,12 +375,10 @@
       		default:
       		{
       			result = getUniqueString(field);
  -    			break;	
  +    			break;
       		}
       	}
       	result = field.getFieldConversion().sqlToJava(result);
           return result;
  -    }    
  -
  -
  +    }
   }
  
  
  
  1.8       +24 -2     db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerNextValImpl.java
  
  Index: SequenceManagerNextValImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerNextValImpl.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- SequenceManagerNextValImpl.java	8 Mar 2003 19:22:56 -0000	1.7
  +++ SequenceManagerNextValImpl.java	1 Apr 2003 14:09:39 -0000	1.8
  @@ -86,7 +86,29 @@
    * <p>
    * Implementation configuration properties:
    * </p>
  - * None.
  + *
  + * <table cellspacing="2" cellpadding="2" border="3" frame="box">
  + * <tr>
  + *     <td><strong>Property Key</strong></td>
  + *     <td><strong>Property Values</strong></td>
  + * </tr>
  + * <tr>
  + *     <td>none</td>
  + *     <td>
  + *
  + *    </td>
  + * </tr>
  + * </table>
  + *
  + *
  + * <br/>
  + * <p>
  + * <b>Limitations:</b>
  + * <ul>
  + *	<li>none</li>
  + * </ul>
  + * </p>
  + * <br/>
    * <br/>
    *
    * @author Edson Carlos Ericksson Richter
  
  
  
  1.4       +51 -18    db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerSeqHiLoImpl.java
  
  Index: SequenceManagerSeqHiLoImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerSeqHiLoImpl.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- SequenceManagerSeqHiLoImpl.java	8 Mar 2003 19:22:56 -0000	1.3
  +++ SequenceManagerSeqHiLoImpl.java	1 Apr 2003 14:09:39 -0000	1.4
  @@ -57,6 +57,8 @@
   import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.broker.metadata.FieldDescriptor;
   
  +import java.util.HashMap;
  +
   /**
    * <p>
    * A High/Low database sequence based implementation.
  @@ -64,16 +66,11 @@
    * for more information.
    * </p>
    *
  - * <b>Limitations:</b>
  - * <ul type="disc">
  - *	<li>do not use when other applications use the database sequence ditto</li>
  - * </ul>
  - *
    * <p>
    * Implementation configuration properties:
    * </p>
    *
  - * <table align="left" cellspacing="2" cellpadding="2" border="1" frame="box" rules="all">
  + * <table cellspacing="2" cellpadding="2" border="3" frame="box">
    * <tr>
    *     <td><strong>Property Key</strong></td>
    *     <td><strong>Property Values</strong></td>
  @@ -88,9 +85,13 @@
    *    </td>
    * </tr>
    * </table>
  - *
  - * <br/>
    * <br/>
  + * <p>
  + * <b>Limitations:</b>
  + * <ul>
  + *	<li>do not use when other applications use the database based sequence ditto</li>
  + * </ul>
  + * </p>
    * <br/>
    * <br/>
    *
  @@ -100,24 +101,56 @@
   public class SequenceManagerSeqHiLoImpl extends SequenceManagerNextValImpl
   {
       public static final String PROPERTY_GRAB_SIZE = SequenceManagerHighLowImpl.PROPERTY_GRAB_SIZE;
  -    protected int grabSize;
  +    private static HashMap hiLoMap = new HashMap();
   
  -    private int counter;
  -    private int maxVal;
  +    protected int grabSize;
   
       public SequenceManagerSeqHiLoImpl(PersistenceBroker broker)
       {
           super(broker);
  -        grabSize = counter = new Integer(getConfigurationProperty(PROPERTY_GRAB_SIZE, "20")).intValue();
  +        grabSize = new Integer(getConfigurationProperty(PROPERTY_GRAB_SIZE, "20")).intValue();
       }
   
  -    protected int getUniqueId(FieldDescriptor field) throws SequenceManagerException
  +    protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException
       {
  -        if (counter == grabSize)
  +        String sequenceName = SequenceManagerHelper.buildSequenceName(getBrokerForClass(), field);
  +        // we have to be threadsafe
  +        synchronized (hiLoMap)
  +        {
  +            HiLoEntry entry = (HiLoEntry) hiLoMap.get(sequenceName);
  +            if (entry == null)
  +            {
  +                entry = new HiLoEntry(grabSize, grabSize);
  +                hiLoMap.put(sequenceName, entry);
  +            }
  +            if (entry.needNewSequence())
  +            {
  +                entry.maxVal = grabSize * (super.getUniqueLong(field) + 1);
  +                entry.counter = 0;
  +            }
  +            return entry.nextVal();
  +        }
  +    }
  +
  +    class HiLoEntry
  +    {
  +        long maxVal;
  +        long counter;
  +
  +        public HiLoEntry(long maxVal, long counter)
  +        {
  +            this.maxVal = maxVal;
  +            this.counter = counter;
  +        }
  +
  +        boolean needNewSequence()
  +        {
  +            return counter == grabSize;
  +        }
  +
  +        long nextVal()
           {
  -            maxVal = grabSize * (super.getUniqueId(field) + 1);
  -            counter = 0;
  +            return maxVal + counter++;
           }
  -        return maxVal + counter++;
       }
   }
  
  
  
  1.1                  db-ojb/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerStoredProcedureImpl.java
  
  Index: SequenceManagerStoredProcedureImpl.java
  ===================================================================
  package org.apache.ojb.broker.util.sequence;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache ObjectRelationalBridge" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import org.apache.commons.lang.SystemUtils;
  import org.apache.ojb.broker.PersistenceBroker;
  import org.apache.ojb.broker.accesslayer.LookupException;
  import org.apache.ojb.broker.metadata.ClassDescriptor;
  import org.apache.ojb.broker.metadata.FieldDescriptor;
  import org.apache.ojb.broker.query.Query;
  import org.apache.ojb.broker.util.logging.Logger;
  import org.apache.ojb.broker.util.logging.LoggerFactory;
  
  import java.sql.CallableStatement;
  import java.sql.SQLException;
  import java.sql.Statement;
  import java.sql.Types;
  
  /**
   * This solution will give those seeking an oracle-style
   * sequence generator a final answer (Identity columns really suck).
   * <br/>
   * The <code>SequenceManagerStoredProcedureImpl</code> implementation enabled database
   * sequence key generation for all databases (e.g. MSSQL, MySQL, DB2, ...)
   * with a <b>JDBC 2.0</b> compliant driver.
   * <br/>
   * First add a new table <code>OJB_NEXTVAL</code> to
   * your database.
   * <pre>
   * CREATE TABLE OJB_NEXTVAL
   * (
   *     SEQ_NAME    VARCHAR(150) NOT NULL,
   *     MAX_KEY     BIGINT,
   *     CONSTRAINT SYS_PK_OJB_NEXTVAL PRIMARY KEY(SEQ_NAME)
   * )
   * </pre>
   * You will also need the stored procedure OJB_NEXTVAL
   * will will take care of giving you a guaranteed unique
   * sequence number, in multi server environments.
   * <br/>
   * <pre>
   * CREATE PROCEDURE ojb_nextval @SEQ_NAME varchar(100)
   *              AS
   *		declare @MAX_KEY BIGINT
   *              -- return an error if sequence does not exist
   *              -- so we will know if someone truncates the table
   *              set @MAX_KEY = 0
   *
   *              UPDATE OJB_NEXTVAL
   *              SET    @MAX_KEY = MAX_KEY = MAX_KEY + 1
   *              WHERE  TABLENAME = @SEQ_NAME
   *
   *		if @MAX_KEY = 0
   *			select 1/0
   *		else
   *			select @MAX_KEY
   *
   *              RETURN @MAX_KEY
   * </pre>
   * <br/>
   * It is possible to define a <code>sequence-name</code>
   * field-descriptor attribute in the repository file. If
   * such an attribute was not found, the implementation build
   * an extent aware sequence name by its own.
   * <br/>
   * Keep in mind when define a sequence name, that you are responsible
   * to be aware of extents, that is: if you ask for an uid for an
   * interface with several
   * implementor classes, or a baseclass with several subclasses the returned
   * uid have to be unique accross all tables representing objects of the
   * extent in question. Thus you have to use the same <code>sequence-name</code>
   * for all extents.
   *
   * <p>
   * Implementation configuration properties:
   * </p>
   *
   * <table cellspacing="2" cellpadding="2" border="3" frame="box">
   * <tr>
   *     <td><strong>Property Key</strong></td>
   *     <td><strong>Property Values</strong></td>
   * </tr>
   * <tr>
   *     <td>none</td>
   *     <td>
   *
   *    </td>
   * </tr>
   * </table>
   *
   * <p>
   * <b>Limitations:</b>
   * <ul>
   *	<li>do not use when other application use the native key generation ditto</li>
   * </ul>
   * </p>
   * <br/>
   * <br/>
   *
   * @author Ryan Vanderwerf
   * @author Edson Carlos Ericksson Richter
   * @author Rajeev Kaul
   * @author Thomas Mahler
   * @author Armin Waibel
   * @version $Id: SequenceManagerStoredProcedureImpl.java,v 1.1 2003/04/01 14:09:39 arminw Exp $
   */
  public class SequenceManagerStoredProcedureImpl extends AbstractSequenceManager
  {
      private Logger log = LoggerFactory.getLogger(SequenceManagerStoredProcedureImpl.class);
      protected static final String PROCEDURE_NAME = "ojb_nextval";
      protected static final String SEQ_NAME_STRING = "SEQ_NAME";
      protected static final String SEQ_ID_STRING = "MAX_KEY";
      protected static final String SEQ_TABLE_NAME = "OJB_NEXTVAL";
  
      /**
       *
       */
      public SequenceManagerStoredProcedureImpl(PersistenceBroker broker)
      {
          super(broker);
      }
  
      protected String sp_createSequenceQuery(String sequenceName, long maxKey)
      {
          String result = "insert into " + SEQ_TABLE_NAME + " ("
                  + SEQ_NAME_STRING + "," + SEQ_ID_STRING +
                  ") values ('" + sequenceName + "'," + maxKey + ")";
          return result;
      }
  
      protected String sp_buildProcedureString(String sequenceName)
      {
          return "{ call " + PROCEDURE_NAME + " (?, ?)" + "}";
      }
  
      protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException
      {
          long result = 0;
          /*
          arminw:
          we obtain a new PB instance to make
          */
          PersistenceBroker targetBroker = getBrokerForClass();
          // lookup sequence name
          String sequenceName = SequenceManagerHelper.buildSequenceName(getBrokerForClass(), field);
          try
          {
              result = buildNextSequence(targetBroker, field.getClassDescriptor(), sequenceName);
              /*
              if 0 was returned we assume that the stored procedure
              did not work properly.
              */
              if (result == 0)
              {
                  throw new SequenceManagerException("No incremented value retrieved");
              }
          }
          catch (Exception e)
          {
              // maybe the sequence was not created
              log.info("Could not grap next key, message was " + e.getMessage() +
                      " - try to write a new sequence entry to database");
              try
              {
                  // on create, make sure to get the max key for the table first
                  long maxKey = SequenceManagerHelper.getMaxForExtent(getBrokerForClass(), field);
                  createSequence(targetBroker, field, sequenceName, maxKey);
              }
              catch (Exception e1)
              {
                  String eol = SystemUtils.LINE_SEPARATOR;
                  throw new SequenceManagerException(eol + "Could not grab next id, failed with " + eol +
                          e.getMessage() + eol + "Creation of new sequence failed with " +
                          eol + e1.getMessage() + eol, e1);
              }
              try
              {
                  result = buildNextSequence(targetBroker, field.getClassDescriptor(), sequenceName);
              }
              catch (Exception e1)
              {
                  throw new SequenceManagerException("Could not grab next id, sequence seems to exist", e);
              }
          }
          return result;
      }
  
      protected long buildNextSequence(PersistenceBroker broker, ClassDescriptor cld, String sequenceName)
              throws LookupException, SQLException
      {
          CallableStatement cs = null;
          try
          {
              String sp = "{ call " + PROCEDURE_NAME + " (?, ?)}";
              cs = broker.serviceConnectionManager().
                      getConnection().prepareCall(sp);
              cs.setString(1, sequenceName);
              cs.registerOutParameter(2, Types.INTEGER);
              cs.executeUpdate();
              // cs.getLong(2);
              return cs.getLong(2);
          }
          finally
          {
              try
              {
                  if (cs != null)
                      cs.close();
              }
              catch (SQLException ignore)
              {
              }
          }
      }
  
      protected void createSequence(PersistenceBroker broker, FieldDescriptor field,
                                    String sequenceName, long maxKey) throws Exception
      {
          Statement stmt = null;
          try
          {
              stmt = getBrokerForClass().serviceStatementManager().getGenericStatement(field.getClassDescriptor(), Query.NOT_SCROLLABLE);
              stmt.execute(sp_createSequenceQuery(sequenceName, maxKey));
          }
          catch (Exception e)
          {
              e.printStackTrace();
              throw new SequenceManagerException("Could create new row in OJB_HL_SEQ table - TABLENAME=" +
                      sequenceName + " field=" + field.getColumnName(), e);
          }
          finally
          {
              try
              {
                  if (stmt != null) stmt.close();
              }
              catch (SQLException ignore)
              {
              }
          }
      }
  }
  
  
  

Mime
View raw message