FileDocCategorySizeDatePackage
JDBCGenerator.javaAPI DocExample4829Wed Aug 23 21:56:52 BST 2000com.imaginary.lwp.jdbc

JDBCGenerator.java

/* $Id: JDBCGenerator.java,v 1.1 1999/11/07 19:32:30 borg Exp $ */
/* Copyright © 1999 George Reese, All Rights Reserved */
package com.imaginary.lwp.jdbc;

import com.imaginary.lwp.SequenceException;
import com.imaginary.lwp.SequenceGenerator;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * A JDBC-based sequence generator that implements LWP's
 * <CODE>SequenceGenerator</CODE> interface. To use this sequence
 * generator, your database must have the following data model:
 * <PRE>
 * CREATE TABLE ORA_SEQGEN (
 *     NAME           VARCHAR(25)     NOT NULL PRIMARY KEY,
 *     NEXT_SEQ       BIGINT          NOT NULL DEFAULT 1,
 *     LUTS           BIGINT          NOT NULL);
 * 
 * CREATE UNIQUE INDEX SEQGEN_IDX ON ORA_SEQGEN(NAME, LUTS);
 * </PRE>
 * <BR>
 * Last modified $Date: 1999/11/07 19:32:30 $
 * @version $Revision: 1.1 $
 * @author George Reese (borg@imaginary.com)
 */
public class JDBCGenerator extends SequenceGenerator {
    /**
     * The SQL to insert a new sequence number in the table.
     */
    static public final String INSERT =
        "INSERT INTO ORA_SEQGEN (NAME, NEXT_SEQ, LUTS) " +
        "VALUES(?, ?, ?)";

    /**
     * Selects the next sequence number from the database.
     */
    static public final String SELECT = 
        "SELECT NEXT_SEQ, LUTS " +
        "FROM ORA_SEQGEN " +
        "WHERE NAME = ?";

    /**
     * The SQL to one-up the current sequence number.
     */
    static public final String UPDATE =
        "UPDATE ORA_SEQGEN " +
        "SET NEXT_SEQ = ?, " +
        "LUTS = ? " +
        "WHERE NAME = ? " +
        "AND LUTS = ?";

    /**
     * Creates a new sequence.
     * @param conn the JDBC connection to use
     * @param seq the sequence name
     * @throws java.sql.SQLException a database error occurred
     */
    private void createSequence(Connection conn, String seq)
        throws SQLException {
        PreparedStatement stmt = conn.prepareStatement(INSERT);

        stmt.setString(1, seq);
        stmt.setLong(2, 1L);
        stmt.setLong(3, (new java.util.Date()).getTime());
        stmt.executeUpdate();
    }

    /**
     * Generates a sequence for the specified sequence in accordance with
     * the <CODE>SequenceGenerator</CODE> interface.
     * @param seq the name of the sequence to generate
     * @return the next value in the sequence
     * @throws com.imaginary.lwp.SequenceException an error occurred
     * generating the sequence
     */
    public synchronized long generate(String seq) throws SequenceException {
        Connection conn = null;
        
        try {
            PreparedStatement stmt;
            ResultSet rs;
            long nid, lut, tut;
            
            conn = JDBCTransactionImpl.getJDBCConnection();
            stmt = conn.prepareStatement(SELECT);
            stmt.setString(1, seq);
            rs = stmt.executeQuery();
            if( !rs.next() ) {
                try {
                    createSequence(conn, seq);
                }
                catch( SQLException e ) {
                    String state = e.getSQLState();

                    // if a duplicate was found, retry sequence generation
                    if( state.equalsIgnoreCase("SQL0803N") ) {
                        return generate(seq);
                    }
                    throw new SequenceException("Database error: " +
                                                e.getMessage());
                }
                return 0L;
            }
            nid = rs.getLong(1);
            lut = rs.getLong(2);
            tut = (new java.util.Date()).getTime();
            if( tut == lut ) {
                tut++;
            }
            stmt = conn.prepareStatement(UPDATE);
            stmt.setLong(1, nid+1);
            stmt.setLong(2, tut);
            stmt.setString(3, seq);
            stmt.setLong(4, lut);
            try {
                stmt.executeUpdate();
                conn.commit();
            }
            catch( SQLException e ) {
                String state = e.getSQLState();

                // someone else grabbed the row,
                // we need to try again
                if( state.equals("SQL0100W") ) {
                    return generate(seq);
                }
                throw new SequenceException("Database error: " +
                                            e.getMessage());
            }
            return nid;
        }
        catch( SQLException e ) {
            throw new SequenceException("Database error: " +
                                        e.getMessage());
        }
        finally {
            if( conn != null ) {
                try { conn.close(); }
                catch( SQLException e ) { }
            }
        }
    }
}