001package io.ebean.config.dbplatform;
002
003import io.ebean.Transaction;
004import io.ebean.util.JdbcClose;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008import javax.persistence.PersistenceException;
009import javax.sql.DataSource;
010import java.sql.Connection;
011import java.sql.PreparedStatement;
012import java.sql.ResultSet;
013import java.sql.SQLException;
014
015/**
016 * A very simple Database sequence based IdGenerator.
017 * <p>
018 * One which batch requests sequence Id's would be better for performance.
019 * </p>
020 */
021public class SimpleSequenceIdGenerator implements PlatformIdGenerator {
022
023  private static final Logger logger = LoggerFactory.getLogger(SimpleSequenceIdGenerator.class);
024
025  private final String sql;
026
027  private final DataSource dataSource;
028
029  private final String seqName;
030
031  /**
032   * Construct given a dataSource and sql to return the next sequence value.
033   */
034  public SimpleSequenceIdGenerator(DataSource dataSource, String sql, String seqName) {
035    this.dataSource = dataSource;
036    this.sql = sql;
037    this.seqName = seqName;
038  }
039
040  @Override
041  public String getName() {
042    return seqName;
043  }
044
045  @Override
046  public boolean isDbSequence() {
047    return true;
048  }
049
050  @Override
051  public void preAllocateIds(int batchSize) {
052    // just ignore this
053  }
054
055  @Override
056  public Object nextId(Transaction t) {
057
058    boolean useTxnConnection = t != null;
059
060    Connection c = null;
061    PreparedStatement pstmt = null;
062    ResultSet rset = null;
063    try {
064      c = useTxnConnection ? t.getConnection() : dataSource.getConnection();
065      pstmt = c.prepareStatement(sql);
066      rset = pstmt.executeQuery();
067      if (rset.next()) {
068        return rset.getInt(1);
069      } else {
070        String m = "Always expecting 1 row from " + sql;
071        throw new PersistenceException(m);
072      }
073    } catch (SQLException e) {
074      throw new PersistenceException("Error getting sequence nextval", e);
075
076    } finally {
077      if (useTxnConnection) {
078        closeResources(rset, pstmt, null);
079      } else {
080        closeResources(rset, pstmt, c);
081      }
082    }
083  }
084
085  private void closeResources(ResultSet rset, PreparedStatement pstmt, Connection c) {
086    JdbcClose.close(rset);
087    JdbcClose.close(pstmt);
088    JdbcClose.close(c);
089  }
090
091}