1 22 package org.jboss.ejb.plugins.keygenerator.hilo; 23 import org.jboss.ejb.plugins.keygenerator.KeyGenerator; 24 import org.jboss.ejb.plugins.cmp.jdbc.JDBCUtil; 25 import org.jboss.logging.Logger; 26 27 import javax.sql.DataSource ; 28 import javax.transaction.TransactionManager ; 29 import javax.transaction.Transaction ; 30 import javax.transaction.SystemException ; 31 import java.sql.PreparedStatement ; 32 import java.sql.Connection ; 33 import java.sql.SQLException ; 34 import java.sql.ResultSet ; 35 39 public class HiLoKeyGenerator 40 implements KeyGenerator 41 { 42 private static long highestHi = 0; 43 44 public static synchronized long getHighestHi() 45 { 46 return highestHi; 47 } 48 49 public static synchronized void setHighestHi(long highestHi) 50 { 51 HiLoKeyGenerator.highestHi = highestHi; 52 } 53 54 private final Logger log; 55 private final DataSource ds; 56 private final long blockSize; 57 58 private long hi; 59 private long lo; 60 61 private TransactionManager tm; 62 private String updateHiSql; 63 private String selectHiSql; 64 65 public HiLoKeyGenerator( 66 DataSource ds, 67 String tableName, 68 String sequenceColumn, 69 String sequenceName, 70 String idColumnName, 71 String selectHiSql, 72 long blockSize, 73 TransactionManager tm 74 ) 75 { 76 this.ds = ds; 77 this.blockSize = blockSize; 78 this.tm = tm; 79 this.log = Logger.getLogger(getClass().getName() + "#" + tableName + "_" + sequenceName); 80 81 updateHiSql = "update " + 82 tableName + 83 " set " + 84 idColumnName + 85 "=?" + 86 " where " + sequenceColumn + "='" + sequenceName + "' and " + 87 idColumnName + "=?"; 88 89 this.selectHiSql = selectHiSql; 90 } 91 92 public synchronized Object generateKey() 93 { 94 if(lo < hi) 95 { 96 ++lo; 97 } 98 else 99 { 100 Transaction curTx = null; 101 try 102 { 103 curTx = tm.suspend(); 104 } 105 catch(SystemException e) 106 { 107 throw new IllegalStateException ("Failed to suspend current transaction."); 108 } 109 110 try 111 { 112 tm.begin(); 113 } 114 catch(Exception e) 115 { 116 throw new IllegalStateException ("Failed to begin a new transaction."); 117 } 118 119 try 120 { 121 doGenerate(); 122 tm.commit(); 123 } 124 catch(SQLException e) 125 { 126 log.error("Failed to update table: " + e.getMessage(), e); 127 128 try 129 { 130 tm.rollback(); 131 } 132 catch(SystemException e1) 133 { 134 log.error("Failed to rollback.", e1); 135 } 136 137 throw new IllegalStateException (e.getMessage()); 138 } 139 catch(Exception e) 140 { 141 log.error("Failed to commit.", e); 142 } 143 finally 144 { 145 if(curTx != null) 146 { 147 try 148 { 149 tm.resume(curTx); 150 } 151 catch(Exception e) 152 { 153 throw new IllegalStateException ("Failed to resume transaction: " + e.getMessage()); 154 } 155 } 156 } 157 } 158 159 return new Long (lo); 160 } 161 162 private void doGenerate() throws SQLException 163 { 164 long curHi; 165 do 166 { 167 curHi = getCurrentHi(); 168 lo = curHi + 1; 169 hi = curHi + blockSize; 170 } 171 while(!updateHi(curHi, hi)); 172 } 173 174 private long getCurrentHi() throws SQLException 175 { 176 return selectHiSql != null ? selectHi() : getHighestHi(); 177 } 178 179 private boolean updateHi(long curHi, long newHi) throws SQLException 180 { 181 if(selectHiSql == null) 182 { 183 setHighestHi(newHi); 184 } 185 return updateTable(curHi, newHi); 186 } 187 188 private long selectHi() throws SQLException 189 { 190 Connection con = null; 191 PreparedStatement selectHiSt = null; 192 ResultSet rs = null; 193 194 if(log.isTraceEnabled()) 195 { 196 log.trace("Executing SQL: " + selectHiSql); 197 } 198 199 try 200 { 201 con = ds.getConnection(); 202 selectHiSt = con.prepareStatement(selectHiSql); 203 rs = selectHiSt.executeQuery(); 204 if(!rs.next()) 205 { 206 throw new IllegalStateException ("The sequence has not been initialized in the service start phase!"); 207 } 208 return rs.getLong(1); 209 } 210 finally 211 { 212 JDBCUtil.safeClose(rs); 213 JDBCUtil.safeClose(selectHiSt); 214 JDBCUtil.safeClose(con); 215 } 216 } 217 218 private boolean updateTable(long curHi, long newHi) throws SQLException 219 { 220 Connection con = null; 221 PreparedStatement updateHi = null; 222 223 if(log.isTraceEnabled()) 224 { 225 log.trace("Executing SQL: " + updateHiSql + ", [" + newHi + "," + curHi + "]"); 226 } 227 228 try 229 { 230 con = ds.getConnection(); 231 updateHi = con.prepareStatement(updateHiSql); 232 updateHi.setLong(1, newHi); 233 updateHi.setLong(2, curHi); 234 return updateHi.executeUpdate() == 1; 235 } 236 finally 237 { 238 JDBCUtil.safeClose(updateHi); 239 JDBCUtil.safeClose(con); 240 } 241 } 242 } | Popular Tags |