1 22 package org.jboss.ejb.txtimer; 23 24 26 import java.io.Serializable ; 27 import java.util.Date ; 28 import java.util.Timer ; 29 import java.util.TimerTask ; 30 31 import javax.ejb.EJBException ; 32 import javax.ejb.NoSuchObjectLocalException ; 33 import javax.ejb.TimerHandle ; 34 import javax.transaction.Status ; 35 import javax.transaction.Synchronization ; 36 import javax.transaction.Transaction ; 37 38 import org.jboss.ejb.AllowedOperationsAssociation; 39 import org.jboss.logging.Logger; 40 41 52 public class TimerImpl implements javax.ejb.Timer , Synchronization 53 { 54 private static Logger log = Logger.getLogger(TimerImpl.class); 56 57 76 private static final int CREATED = 0; 77 private static final int STARTED_IN_TX = 1; 78 private static final int ACTIVE = 2; 79 private static final int CANCELED_IN_TX = 3; 80 private static final int CANCELED = 4; 81 private static final int EXPIRED = 5; 82 private static final int IN_TIMEOUT = 6; 83 private static final int RETRY_TIMEOUT = 7; 84 85 private static final String [] TIMER_STATES = {"created", "started_in_tx", "active", "canceled_in_tx", 86 "canceled", "expired", "in_timeout", "retry_timeout"}; 87 88 private TimerServiceImpl timerService; 90 private String timerId; 91 private TimedObjectId timedObjectId; 92 private TimedObjectInvoker timedObjectInvoker; 93 private Date firstTime; 94 private long periode; 95 private Serializable info; 96 97 private long nextExpire; 98 private int timerState; 99 private Timer utilTimer; 100 private int hashCode; 101 102 105 TimerImpl(TimerServiceImpl timerService, String timerId, TimedObjectId timedObjectId, TimedObjectInvoker timedObjectInvoker, Serializable info) 106 { 107 this.timerService = timerService; 108 this.timerId = timerId; 109 this.timedObjectId = timedObjectId; 110 this.timedObjectInvoker = timedObjectInvoker; 111 this.info = info; 112 113 setTimerState(CREATED); 114 } 115 116 void startTimer(Date firstTime, long periode) 117 { 118 this.firstTime = firstTime; 119 this.nextExpire = firstTime.getTime(); 120 this.periode = periode; 121 122 timerService.addTimer(this); 123 registerTimerWithTx(); 124 125 startInTx(); 127 } 128 129 public String getTimerId() 130 { 131 return timerId; 132 } 133 134 public TimedObjectId getTimedObjectId() 135 { 136 return timedObjectId; 137 } 138 139 public Date getFirstTime() 140 { 141 return firstTime; 142 } 143 144 public long getPeriode() 145 { 146 return periode; 147 } 148 149 public long getNextExpire() 150 { 151 return nextExpire; 152 } 153 154 public Serializable getInfoInternal() 155 { 156 return info; 157 } 158 159 public boolean isActive() 160 { 161 return !isCanceled() && !isExpired(); 162 } 163 164 public boolean isInRetry() { 165 return timerState == RETRY_TIMEOUT; 166 } 167 168 public boolean isCanceled() 169 { 170 return timerState == CANCELED_IN_TX || timerState == CANCELED; 171 } 172 173 public boolean isExpired() 174 { 175 return timerState == EXPIRED; 176 } 177 178 187 public void cancel() throws IllegalStateException , NoSuchObjectLocalException , EJBException 188 { 189 assertTimedOut(); 190 assertAllowedOperation("Timer.cancel"); 191 registerTimerWithTx(); 192 cancelInTx(); 193 } 194 195 198 public void killTimer() 199 { 200 log.debug("killTimer: " + this); 201 if (timerState != EXPIRED) 202 setTimerState(CANCELED); 203 timerService.removeTimer(this); 204 utilTimer.cancel(); 205 } 206 207 210 public void stopTimer() 211 { 212 log.debug("stopTimer: " + this); 213 if (timerState != EXPIRED) 214 setTimerState(CANCELED); 215 utilTimer.cancel(); 216 } 217 218 228 public long getTimeRemaining() throws IllegalStateException , NoSuchObjectLocalException , EJBException 229 { 230 assertTimedOut(); 231 assertAllowedOperation("Timer.getTimeRemaining"); 232 return nextExpire - System.currentTimeMillis(); 233 } 234 235 245 public Date getNextTimeout() throws IllegalStateException , NoSuchObjectLocalException , EJBException 246 { 247 assertTimedOut(); 248 assertAllowedOperation("Timer.getNextTimeout"); 249 return new Date (nextExpire); 250 } 251 252 263 public Serializable getInfo() throws IllegalStateException , NoSuchObjectLocalException , EJBException 264 { 265 assertTimedOut(); 266 assertAllowedOperation("Timer.getInfo"); 267 return info; 268 } 269 270 281 public TimerHandle getHandle() throws IllegalStateException , NoSuchObjectLocalException , EJBException 282 { 283 assertTimedOut(); 284 assertAllowedOperation("Timer.getHandle"); 285 return new TimerHandleImpl(this); 286 } 287 288 291 public boolean equals(Object obj) 292 { 293 if (obj == this) return true; 294 if (obj instanceof TimerImpl) 295 { 296 TimerImpl other = (TimerImpl)obj; 297 return hashCode() == other.hashCode(); 298 } 299 return false; 300 } 301 302 305 public int hashCode() 306 { 307 if (hashCode == 0) 308 { 309 String hash = "[" + timerId + "," + timedObjectId + "," + firstTime + "," + periode + "]"; 310 hashCode = hash.hashCode(); 311 } 312 return hashCode; 313 } 314 315 318 public String toString() 319 { 320 long remaining = nextExpire - System.currentTimeMillis(); 321 String retStr = "[id=" + timerId + ",target=" + timedObjectId + ",remaining=" + remaining + ",periode=" + periode + 322 "," + TIMER_STATES[timerState] + "]"; 323 return retStr; 324 } 325 326 329 private void registerTimerWithTx() 330 { 331 Transaction tx = timerService.getTransaction(); 332 if (tx != null) 333 { 334 try 335 { 336 tx.registerSynchronization(this); 337 } 338 catch (Exception e) 339 { 340 log.error("Cannot register txtimer with Tx: " + this); 341 } 342 } 343 } 344 345 private void setTimerState(int state) 346 { 347 log.debug("setTimerState: " + TIMER_STATES[state]); 348 timerState = state; 349 350 if (timerState == EXPIRED) 352 killTimer(); 353 } 354 355 private void startInTx() 356 { 357 utilTimer = new Timer (); 358 359 if (timerService.getTransaction() != null) 360 { 361 setTimerState(STARTED_IN_TX); 363 } 364 else 365 { 366 scheduleTimeout(); 367 setTimerState(ACTIVE); 368 } 369 } 370 371 private void cancelInTx() 372 { 373 if (timerService.getTransaction() != null) 374 setTimerState(CANCELED_IN_TX); 375 else 376 killTimer(); 377 } 378 379 private void scheduleTimeout() 380 { 381 if (periode > 0) 382 utilTimer.schedule(new TimerTaskImpl(this), new Date (nextExpire), periode); 383 else 384 utilTimer.schedule(new TimerTaskImpl(this), new Date (nextExpire)); 385 } 386 387 390 private void assertTimedOut() 391 { 392 if (timerState == EXPIRED) 393 throw new NoSuchObjectLocalException ("Timer has expired"); 394 if (timerState == CANCELED_IN_TX || timerState == CANCELED) 395 throw new NoSuchObjectLocalException ("Timer was canceled"); 396 } 397 398 401 private void assertAllowedOperation(String timerMethod) 402 { 403 AllowedOperationsAssociation.assertAllowedIn(timerMethod, 404 AllowedOperationsAssociation.IN_BUSINESS_METHOD | 405 AllowedOperationsAssociation.IN_EJB_TIMEOUT | 406 AllowedOperationsAssociation.IN_SERVICE_ENDPOINT_METHOD | 407 AllowedOperationsAssociation.IN_AFTER_BEGIN | 408 AllowedOperationsAssociation.IN_BEFORE_COMPLETION | 409 AllowedOperationsAssociation.IN_EJB_POST_CREATE | 410 AllowedOperationsAssociation.IN_EJB_REMOVE | 411 AllowedOperationsAssociation.IN_EJB_LOAD | 412 AllowedOperationsAssociation.IN_EJB_STORE); 413 } 414 415 417 422 public void beforeCompletion() 423 { 424 } 425 426 432 public void afterCompletion(int status) 433 { 434 if (status == Status.STATUS_COMMITTED) 435 { 436 log.debug("commit: " + this); 437 438 switch (timerState) 439 { 440 case STARTED_IN_TX: 441 scheduleTimeout(); 442 setTimerState(ACTIVE); 443 break; 444 445 case CANCELED_IN_TX: 446 killTimer(); 447 break; 448 449 case IN_TIMEOUT: 450 case RETRY_TIMEOUT: 451 setTimerState(periode == 0 ? EXPIRED : ACTIVE); 452 break; 453 } 454 } 455 else if (status == Status.STATUS_ROLLEDBACK) 456 { 457 log.debug("rollback: " + this); 458 459 switch (timerState) 460 { 461 case STARTED_IN_TX: 462 killTimer(); 463 break; 464 465 case CANCELED_IN_TX: 466 setTimerState(ACTIVE); 467 break; 468 469 case IN_TIMEOUT: 470 setTimerState(RETRY_TIMEOUT); 471 log.debug("retry: " + this); 472 timerService.retryTimeout(this); 473 break; 474 475 case RETRY_TIMEOUT: 476 setTimerState(periode == 0 ? EXPIRED : ACTIVE); 477 break; 478 } 479 } 480 } 481 482 484 487 private class TimerTaskImpl extends TimerTask 488 { 489 private TimerImpl timer; 490 491 public TimerTaskImpl(TimerImpl timer) 492 { 493 this.timer = timer; 494 } 495 496 499 public void run() 500 { 501 log.debug("run: " + timer); 502 503 if (isActive() && periode > 0) 507 { 508 nextExpire += periode; 509 } 510 511 if (isInRetry()) 514 { 515 log.debug("Timer in retry mode, skipping this scheduled execution"); 516 return; 517 } 518 519 if (isActive()) 520 { 521 try 522 { 523 setTimerState(IN_TIMEOUT); 524 timedObjectInvoker.callTimeout(timer); 525 } 526 catch (Exception e) 527 { 528 log.error("Error invoking ejbTimeout: " + e.toString()); 529 } 530 finally 531 { 532 if (timerState == IN_TIMEOUT) 533 { 534 log.debug("Timer was not registered with Tx, resetting state: " + timer); 535 setTimerState(periode == 0 ? EXPIRED : ACTIVE); 536 } 537 } 538 } 539 } 540 } 541 } 542 | Popular Tags |