1 22 package org.jboss.ejb3.entity; 23 24 import java.io.Serializable ; 25 import java.sql.Connection ; 26 import java.sql.PreparedStatement ; 27 import java.sql.ResultSet ; 28 import java.sql.SQLException ; 29 import java.sql.Types ; 30 import java.util.Properties ; 31 import javax.transaction.SystemException ; 32 import javax.transaction.Transaction ; 33 import javax.transaction.TransactionManager ; 34 import org.apache.commons.logging.Log; 35 import org.apache.commons.logging.LogFactory; 36 import org.hibernate.HibernateException; 37 import org.hibernate.LockMode; 38 import org.hibernate.dialect.Dialect; 39 import org.hibernate.engine.SessionImplementor; 40 import org.hibernate.exception.JDBCExceptionHelper; 41 import org.hibernate.id.Configurable; 42 import org.hibernate.id.IdentifierGenerationException; 43 import org.hibernate.id.IdentifierGeneratorFactory; 44 import org.hibernate.id.PersistentIdentifierGenerator; 45 import org.hibernate.transaction.JBossTransactionManagerLookup; 46 import org.hibernate.transaction.TransactionManagerLookup; 47 import org.hibernate.type.Type; 48 import org.hibernate.util.PropertiesHelper; 49 50 65 public class JTATableIdGenerator implements PersistentIdentifierGenerator, Configurable 66 { 67 68 71 public static final String COLUMN = "column"; 72 73 76 public static final String DEFAULT_COLUMN_NAME = "next_hi"; 77 78 81 public static final String TABLE = "table"; 82 83 86 public static final String DEFAULT_TABLE_NAME = "next_hi"; 87 88 91 public static final String ALLOCATION_SIZE = "allocationSize"; 92 93 96 public static final int DEFAULT_ALLOCATION_SIZE = 20; 97 98 101 private static final Log log = LogFactory.getLog(JTATableIdGenerator.class); 102 103 106 private String tableName; 107 108 111 private String columnName; 112 113 116 private String query; 117 118 121 private String update; 122 123 126 private TransactionManagerLookup transactionManagerLookup; 127 128 131 private Class returnClass; 132 133 137 private int allocationSize; 138 139 public void configure(Type type, Properties params, Dialect dialect) 140 { 141 this.tableName = PropertiesHelper.getString(TABLE, params, DEFAULT_TABLE_NAME); 142 this.columnName = PropertiesHelper.getString(COLUMN, params, DEFAULT_COLUMN_NAME); 143 this.allocationSize = PropertiesHelper.getInt(ALLOCATION_SIZE, params, DEFAULT_ALLOCATION_SIZE); 144 String schemaName = params.getProperty(SCHEMA); 145 String catalogName = params.getProperty(CATALOG); 146 147 if (true) throw new RuntimeException ("DOES ANYBODY USE THIS? It IS CURRENTLY BROKEN"); 148 149 158 159 query = "select " + 161 columnName + 162 " from " + 163 dialect.appendLockHint(LockMode.UPGRADE, tableName) + 164 dialect.getForUpdateString(); 165 update = "update " + 166 tableName + 167 " set " + 168 columnName + 169 " = ? where " + 170 columnName + 171 " = ?"; 172 173 transactionManagerLookup = new JBossTransactionManagerLookup(); 176 177 returnClass = type.getReturnedClass(); 179 180 if (log.isDebugEnabled()) 182 { 183 log.debug("configuring id generator: " + this.getClass().getName()); 184 log.debug("tableName=" + tableName); 185 log.debug("columnName=" + columnName); 186 log.debug("allocationSize=" + allocationSize); 187 log.debug("query=" + query); 188 log.debug("update=" + update); 189 log.debug("returnClass=" + returnClass); 190 } 191 } 192 193 public synchronized Serializable generate(SessionImplementor session, Object object) 194 throws HibernateException 195 { 196 TransactionManager tm = transactionManagerLookup.getTransactionManager(new Properties ()); 199 Transaction surroundingTransaction = null; Connection conn = null; String sql = null; try 203 { 204 long result; 206 surroundingTransaction = tm.suspend(); 208 if (log.isDebugEnabled()) 209 { 210 log.debug("surrounding tx suspended"); 211 } 212 tm.begin(); 213 214 conn = session.getBatcher().openConnection(); 216 217 sql = query; 219 PreparedStatement qps = conn.prepareStatement(query); 220 try 221 { 222 ResultSet rs = qps.executeQuery(); 223 if (!rs.next()) 224 { 225 String err = "could not read sequence value - you need to populate the table: " + tableName; 226 log.error(err); 227 throw new IdentifierGenerationException(err); 228 } 229 result = rs.getLong(1); 230 rs.close(); 231 } 232 catch (SQLException sqle) 233 { 234 log.error("could not read a sequence value", sqle); 235 throw sqle; 236 } 237 finally 238 { 239 qps.close(); 240 } 241 242 sql = update; 244 long sequence = result + 1; 245 PreparedStatement ups = conn.prepareStatement(update); 246 try 247 { 248 ups.setLong(1, sequence); 249 ups.setLong(2, result); 250 ups.executeUpdate(); 251 } 252 catch (SQLException sqle) 253 { 254 log.error("could not update sequence value in: " + tableName, sqle); 255 throw sqle; 256 } 257 finally 258 { 259 ups.close(); 260 } 261 262 tm.commit(); 264 265 Number typedSequence = IdentifierGeneratorFactory.createNumber(sequence, returnClass); 267 if (log.isDebugEnabled()) 268 { 269 log.debug("generate() returned: " + typedSequence); 270 } 271 return typedSequence; 272 } 273 catch (SQLException sqle) 274 { 275 throw JDBCExceptionHelper.convert(session.getFactory().getSQLExceptionConverter(), 276 sqle, 277 "could not get or update next value", 278 sql); 279 } 280 catch (Exception e) 281 { 282 try 283 { 284 tm.rollback(); 285 throw new HibernateException(e); 286 } 287 catch (SystemException e1) 288 { 289 throw new HibernateException(e1); 290 } 291 } 292 finally 293 { 294 if (conn != null) 295 try 296 { 297 conn.close(); 298 } 299 catch (SQLException e) 300 { 301 } 303 if (surroundingTransaction != null) 305 { 306 try 307 { 308 tm.resume(surroundingTransaction); 309 if (log.isDebugEnabled()) 310 { 311 log.debug("surrounding tx resumed"); 312 } 313 } 314 catch (Exception e) 315 { 316 throw new HibernateException(e); 317 } 318 } 319 } 320 } 321 322 323 public String [] sqlCreateStrings(Dialect dialect) throws HibernateException 324 { 325 return new String []{ 326 "create table " + tableName + " ( " + columnName + " " + dialect.getTypeName(Types.BIGINT) + " )", 327 "insert into " + tableName + " values ( 0 )" 328 }; 329 } 330 331 public String [] sqlDropStrings(Dialect dialect) 332 { 333 StringBuffer sqlDropString = new StringBuffer () 335 .append("drop table "); 336 if (dialect.supportsIfExistsBeforeTableName()) 337 { 338 sqlDropString.append("if exists "); 339 } 340 sqlDropString.append(tableName) 341 .append(dialect.getCascadeConstraintsString()); 342 if (dialect.supportsIfExistsAfterTableName()) 343 { 344 sqlDropString.append(" if exists"); 345 } 346 return new String []{sqlDropString.toString()}; 347 } 348 349 public Object generatorKey() 350 { 351 return tableName; 352 } 353 } 354 | Popular Tags |