1 17 18 package org.sape.carbon.services.uniqueid; 19 20 import java.sql.Connection ; 21 import java.sql.PreparedStatement ; 22 import java.sql.ResultSet ; 23 import java.sql.SQLException ; 24 25 import org.sape.carbon.core.component.ComponentConfiguration; 26 import org.sape.carbon.core.component.lifecycle.Configurable; 27 import org.sape.carbon.core.config.InvalidConfigurationException; 28 import org.sape.carbon.core.exception.ExceptionUtility; 29 import org.sape.carbon.services.sql.StatementFactory; 30 import org.sape.carbon.services.sql.StatementFactoryException; 31 import org.sape.carbon.services.sql.connection.ConnectionFactory; 32 33 import org.apache.commons.logging.Log; 34 import org.apache.commons.logging.LogFactory; 35 36 50 public class DefaultUniqueIDServiceImpl 51 implements UniqueIDService, Configurable { 52 53 56 private Log log = 57 LogFactory.getLog(this.getClass()); 58 59 60 protected String idName; 61 62 63 protected long blockSize; 64 65 66 protected long initialBlockStart; 67 68 69 protected long currentBlockStart; 70 71 72 protected long currentBlockEnd; 73 74 75 protected long currentValue; 76 77 78 protected boolean autoCreate; 79 80 81 protected StatementFactory statementFactory; 82 83 84 protected ConnectionFactory connectionFactory; 85 86 87 protected String retrieveStatementName; 88 89 90 protected String updateStatementName; 91 92 93 protected String createStatementName; 94 95 101 protected boolean retrieveNewBlock; 102 103 110 public synchronized long getNextID() 111 throws UniqueIDServiceException { 112 113 if (log.isTraceEnabled()) { 114 log.trace("Getting next value from ID named [" 115 + this.idName + "]"); 116 } 117 118 if (this.retrieveNewBlock 119 || this.currentValue > this.currentBlockEnd) { 120 121 reserveNewBlock(); 122 this.retrieveNewBlock = false; 123 } 124 return this.currentValue++; 125 } 126 127 134 public void configure(ComponentConfiguration configuration) { 135 136 UniqueIDServiceConfiguration config = 137 (UniqueIDServiceConfiguration) configuration; 138 139 this.idName = config.getIDName(); 141 this.autoCreate = config.isAutoCreate(); 142 this.blockSize = config.getBlockSize(); 143 this.initialBlockStart = config.getInitialBlockStart(); 144 this.statementFactory = config.getStatementFactory(); 145 this.connectionFactory = config.getConnectionFactory(); 146 this.retrieveStatementName = config.getRetrieveStatementName(); 147 this.updateStatementName = config.getUpdateStatementName(); 148 this.createStatementName = config.getCreateStatementName(); 149 150 if (this.idName == null) { 152 throw new InvalidConfigurationException( 153 this.getClass(), 154 config.getConfigurationName(), 155 "IDName", 156 "Cannot be null"); 157 } 158 159 if (this.statementFactory == null) { 160 throw new InvalidConfigurationException( 161 this.getClass(), 162 config.getConfigurationName(), 163 "StatementFactory", 164 "Cannot be null"); 165 } 166 167 if (this.connectionFactory == null) { 168 throw new InvalidConfigurationException( 169 this.getClass(), 170 config.getConfigurationName(), 171 "ConnectionFactory", 172 "Cannot be null"); 173 } 174 175 this.retrieveNewBlock = true; 178 179 } 180 181 193 private boolean isSecondAttemptRequired = true; 194 195 203 protected void reserveNewBlock() throws UniqueIDServiceException { 204 205 if (log.isInfoEnabled()) { 206 log.info("Reserving [" + this.blockSize + "] on Unique ID [" 207 + this.idName + "]."); 208 } 209 210 Connection connection = null; 211 try { 212 213 connection = this.connectionFactory.getConnection(); 214 connection.setAutoCommit(false); 215 216 long start; 217 218 try { 219 start = retrieveBlockStart(connection); 220 } catch (UniqueIDNotFoundException uidnfe) { 221 if (this.autoCreate) { 222 try { 224 start = createUniqueID(); 225 } catch (SQLException sqle) { 226 227 if (isSecondAttemptRequired) { 230 isSecondAttemptRequired = false; 231 start = retrieveBlockStart(connection); 232 } else { 233 throw uidnfe; 234 } 235 } 236 } else { 237 throw uidnfe; 239 } 240 } 241 242 long nextBlockStart = start + this.blockSize; 243 reserveBlock(nextBlockStart, connection); 244 245 connection.commit(); 247 this.currentBlockStart = start; 248 this.currentBlockEnd = nextBlockStart - 1; 251 this.currentValue = this.currentBlockStart; 253 254 } catch (SQLException se) { 255 try { 256 if (connection != null) { 258 connection.rollback(); 259 } 260 } catch (SQLException sqle) { 261 if (log.isWarnEnabled()) { 262 log.warn("Caught exception rolling back unique id update: " 263 + sqle 264 + ExceptionUtility.captureStackTrace(sqle)); 265 } 266 } 267 268 throw new UniqueIDServiceException( 270 this.getClass(), 271 this.idName, 272 "Caught SQLException reserving range of ids", 273 se); 274 275 } catch (UniqueIDServiceException uidse) { 276 try { 277 if (connection != null) { 279 connection.rollback(); 280 } 281 } catch (SQLException sqle) { 282 if (log.isWarnEnabled()) { 283 log.warn("Caught exception rolling back unique id update: " 284 + sqle 285 + ExceptionUtility.captureStackTrace(sqle)); 286 } 287 } 288 289 throw uidse; 291 292 } finally { 293 try { 295 if (connection != null) { 296 connection.close(); 297 } 298 } catch (SQLException se) { 299 if (log.isWarnEnabled()) { 300 log.warn("Caught exception closing Connection: " 301 + se 302 + ExceptionUtility.captureStackTrace(se)); 303 } 304 } 305 } 306 } 307 308 318 protected long retrieveBlockStart(Connection connection) 319 throws UniqueIDNotFoundException, UniqueIDServiceException { 320 321 PreparedStatement retrieveStmt = null; 322 ResultSet retrieveRSet = null; 323 324 try { 326 retrieveStmt = 327 this.statementFactory.createPreparedStatement( 328 this.retrieveStatementName, 329 connection); 330 331 retrieveStmt.setString(1, this.idName); 332 retrieveRSet = retrieveStmt.executeQuery(); 333 334 if (retrieveRSet.next()) { 335 return retrieveRSet.getLong(1); 336 } else { 337 throw new UniqueIDNotFoundException( 338 this.getClass(), this.idName); 339 } 340 341 } catch (StatementFactoryException sfe) { 342 throw new UniqueIDServiceException( 343 this.getClass(), 344 this.idName, 345 "Caught StatementFactoryException retrieving id", 346 sfe); 347 348 } catch (SQLException se) { 349 throw new UniqueIDServiceException( 350 this.getClass(), 351 this.idName, 352 "Caught SQLException retrieving id", 353 se); 354 355 } finally { 356 try { 357 if (retrieveRSet != null) { 358 retrieveRSet.close(); 359 } 360 } catch (SQLException se) { 361 if (log.isWarnEnabled()) { 362 log.warn("Caught exception closing ResultSet: " 363 + se 364 + ExceptionUtility.captureStackTrace(se)); 365 } 366 } 367 368 try { 369 if (retrieveStmt != null) { 370 retrieveStmt.close(); 371 } 372 } catch (SQLException se) { 373 if (log.isWarnEnabled()) { 374 log.warn("Caught exception closing Statement: " 375 + se 376 + ExceptionUtility.captureStackTrace(se)); 377 } 378 } 379 } 380 } 381 382 392 protected void reserveBlock(long nextBlockStart, Connection connection) 393 throws UniqueIDServiceException { 394 395 PreparedStatement updateStmt = null; 396 try { 398 updateStmt = 399 this.statementFactory.createPreparedStatement( 400 this.updateStatementName, 401 connection); 402 403 updateStmt.setLong(1, nextBlockStart); 404 updateStmt.setString(2, this.idName); 405 406 int updates = updateStmt.executeUpdate(); 408 409 if (updates != 1) { 411 throw new UniqueIDServiceException( 412 this.getClass(), 413 this.idName, 414 "Database updated [" + updates + "] rows, expected only 1"); 415 } 416 417 } catch (StatementFactoryException sfe) { 418 throw new UniqueIDServiceException( 419 this.getClass(), 420 this.idName, 421 "Caught StatementFactoryException reserving range of ids", 422 sfe); 423 424 } catch (SQLException se) { 425 throw new UniqueIDServiceException( 426 this.getClass(), 427 this.idName, 428 "Caught SQLException reserving range of ids", 429 se); 430 431 } finally { 432 try { 433 if (updateStmt != null) { 434 updateStmt.close(); 435 } 436 } catch (SQLException se) { 437 if (log.isWarnEnabled()) { 438 log.warn("Caught exception closing Statement: " 439 + se 440 + ExceptionUtility.captureStackTrace(se)); 441 } 442 } 443 } 444 } 445 446 457 protected long createUniqueID() 458 throws UniqueIDCreationException, SQLException { 459 460 if (log.isInfoEnabled()) { 461 log.info("Creating createUniqueID [" + this.idName + "]"); 462 } 463 464 PreparedStatement insertStmt = null; 465 466 try { 467 insertStmt = 468 this.statementFactory.createPreparedStatement( 469 this.createStatementName); 470 471 insertStmt.setString(1, this.idName); 472 insertStmt.setDouble(2, this.initialBlockStart); 473 int updateCount = insertStmt.executeUpdate(); 474 475 if (updateCount != 1) { 476 throw new UniqueIDCreationException( 477 this.getClass(), 478 this.idName, 479 "The update count was [" + updateCount + "], expected 1"); 480 } 481 482 } catch (SQLException se) { 483 if (log.isInfoEnabled()) { 488 log.info("Exception encountered while inserting row " 489 + "in unique id table " + se); 490 } 491 throw se; 492 493 } catch (StatementFactoryException sfe) { 494 throw new UniqueIDCreationException( 495 this.getClass(), 496 this.idName, 497 "Caught StatementFactoryException creating id", 498 sfe); 499 500 } finally { 501 try { 502 if (insertStmt != null) { 503 insertStmt.close(); 504 } 505 } catch (SQLException se) { 506 if (log.isWarnEnabled()) { 507 log.warn("Caught exception closing Statement: " 508 + se 509 + ExceptionUtility.captureStackTrace(se)); 510 } 511 } 512 } 513 514 return this.initialBlockStart; 515 } 516 } | Popular Tags |