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