1 22 package org.jboss.ejb.plugins; 23 24 import java.lang.reflect.Method ; 25 import java.util.TimerTask ; 26 27 import javax.ejb.EJBException ; 28 import javax.transaction.RollbackException ; 29 import javax.transaction.Status ; 30 import javax.transaction.Synchronization ; 31 import javax.transaction.Transaction ; 32 33 import org.jboss.ejb.BeanLock; 34 import org.jboss.ejb.Container; 35 import org.jboss.ejb.EntityCache; 36 import org.jboss.ejb.EntityContainer; 37 import org.jboss.ejb.EntityEnterpriseContext; 38 import org.jboss.ejb.GlobalTxEntityMap; 39 import org.jboss.invocation.Invocation; 40 import org.jboss.metadata.ConfigurationMetaData; 41 import org.jboss.util.NestedRuntimeException; 42 43 61 public class EntitySynchronizationInterceptor extends AbstractInterceptor 62 { 63 64 private ValidContextsRefresher vcr; 65 66 69 protected int commitOption; 70 71 74 protected long optionDRefreshRate; 75 76 79 protected EntityContainer container; 80 81 public Container getContainer() 82 { 83 return container; 84 } 85 86 public void setContainer(Container container) 87 { 88 this.container = (EntityContainer) container; 89 } 90 91 public void create() 92 throws Exception 93 { 94 95 try 96 { 97 ConfigurationMetaData configuration = container.getBeanMetaData().getContainerConfiguration(); 98 commitOption = configuration.getCommitOption(); 99 optionDRefreshRate = configuration.getOptionDRefreshRate(); 100 } 101 catch(Exception e) 102 { 103 log.warn(e.getMessage()); 104 } 105 } 106 107 public void start() 108 { 109 try 110 { 111 if (commitOption == ConfigurationMetaData.D_COMMIT_OPTION) 113 { 114 vcr = new ValidContextsRefresher(); 115 LRUEnterpriseContextCachePolicy.tasksTimer.schedule(vcr, optionDRefreshRate, optionDRefreshRate); 116 log.debug("Scheduled a cache flush every " + optionDRefreshRate/1000 + " seconds"); 117 } 118 } 119 catch(Exception e) 120 { 121 vcr = null; 122 log.warn("problem scheduling valid contexts refresher", e); 123 } 124 } 125 126 public void stop() 127 { 128 if (vcr != null) 129 { 130 TimerTask temp = vcr; 131 vcr = null; 132 temp.cancel(); 133 } 134 } 135 136 protected Synchronization createSynchronization(Transaction tx, EntityEnterpriseContext ctx) 137 { 138 return new InstanceSynchronization(tx, ctx); 139 } 140 141 144 protected void register(EntityEnterpriseContext ctx, Transaction tx) 145 { 146 boolean trace = log.isTraceEnabled(); 147 if(trace) 148 log.trace("register, ctx=" + ctx + ", tx=" + tx); 149 150 EntityContainer ctxContainer = null; 151 try 152 { 153 ctxContainer = (EntityContainer)ctx.getContainer(); 154 if(!ctx.hasTxSynchronization()) 155 { 156 Synchronization synch = createSynchronization(tx, ctx); 158 159 tx.registerSynchronization(synch); 161 162 ctx.hasTxSynchronization(true); 163 } 164 if(!ctxContainer.isReadOnly()) 166 { 167 ctx.getTxAssociation().scheduleSync(tx, ctx); 168 } 169 } 170 catch(RollbackException e) 171 { 172 synchronized(ctx) 174 { 175 ctx.setValid(false); 176 ctx.hasTxSynchronization(false); 177 ctx.setTransaction(null); 178 ctx.setTxAssociation(GlobalTxEntityMap.NONE); 179 } 180 throw new EJBException (e); 181 } 182 catch(Throwable t) 183 { 184 ctx.hasTxSynchronization(false); 186 ctx.setTxAssociation(GlobalTxEntityMap.NONE); 187 if(t instanceof RuntimeException ) 188 throw (RuntimeException )t; 189 else if(t instanceof Error ) 190 throw (Error )t; 191 else if(t instanceof Exception ) 192 throw new EJBException ((Exception )t); 193 else 194 throw new NestedRuntimeException(t); 195 } 196 } 197 198 public Object invokeHome(Invocation mi) throws Exception 199 { 200 EntityEnterpriseContext ctx = (EntityEnterpriseContext)mi.getEnterpriseContext(); 201 Transaction tx = mi.getTransaction(); 202 203 Object rtn = getNext().invokeHome(mi); 204 205 if(ctx.getId() != null) 207 { 208 209 ctx.setValid(true); 211 212 if(tx != null) 213 { 214 BeanLock lock = container.getLockManager().getLock(ctx.getCacheKey()); 215 try 216 { 217 lock.schedule(mi); 218 register(ctx, tx); lock.endInvocation(mi); 220 } 221 finally 222 { 223 container.getLockManager().removeLockRef(lock.getId()); 224 } 225 } 226 } 227 return rtn; 228 } 229 230 public Object invoke(Invocation mi) throws Exception 231 { 232 EntityEnterpriseContext ctx = (EntityEnterpriseContext)mi.getEnterpriseContext(); 234 235 Transaction tx = mi.getTransaction(); 237 238 if(log.isTraceEnabled()) 239 log.trace("invoke called for ctx " + ctx + ", tx=" + tx); 240 241 if(!ctx.isValid()) 242 { 243 container.getPersistenceManager().loadEntity(ctx); 244 ctx.setValid(true); 245 } 246 247 boolean didSetReadOnly = false; 250 if(!ctx.isReadOnly() && 251 (container.isReadOnly() || 252 container.getBeanMetaData().isMethodReadOnly(mi.getMethod()))) 253 { 254 ctx.setReadOnly(true); 255 didSetReadOnly = true; 256 } 257 258 260 try 262 { 263 if(tx != null && tx.getStatus() != Status.STATUS_NO_TRANSACTION) 264 { 265 boolean isReadOnly = container.isReadOnly(); 267 if(isReadOnly == false) 268 { 269 Method method = mi.getMethod(); 270 if(method != null) 271 isReadOnly = container.getBeanMetaData().isMethodReadOnly(method.getName()); 272 } 273 try 274 { 275 if(isReadOnly == false) 276 { 277 register(ctx, tx); 281 } 282 283 Object retVal = getNext().invoke(mi); 285 286 if(isReadOnly == false) 290 { 291 register(ctx, tx); 295 } 296 297 return retVal; 299 } 300 finally 301 { 302 if(isReadOnly && ctx.hasTxSynchronization() == false) 304 { 305 switch(commitOption) 306 { 307 case ConfigurationMetaData.B_COMMIT_OPTION: 309 ctx.setValid(false); 311 break; 312 313 case ConfigurationMetaData.C_COMMIT_OPTION: 315 try 316 { 317 if(ctx.getId() != null) 322 container.getInstanceCache().remove(ctx.getId()); 323 } 324 catch(Exception e) 325 { 326 log.debug("Exception releasing context", e); 327 } 328 break; 329 } 330 } 331 } 332 } 333 else 334 { 335 try 337 { 338 Object result = getNext().invoke(mi); 339 340 if(ctx.getId() != null && !container.isReadOnly()) 343 { 344 container.invokeEjbStore(ctx); 345 container.storeEntity(ctx); 346 } 347 348 return result; 349 } 350 catch(Exception e) 351 { 352 ctx.setValid(false); 354 throw e; 355 } 356 finally 357 { 358 switch(commitOption) 359 { 360 case ConfigurationMetaData.B_COMMIT_OPTION: 362 ctx.setValid(false); 364 break; 365 366 case ConfigurationMetaData.C_COMMIT_OPTION: 368 try 369 { 370 if(ctx.getId() != null) 378 container.getInstanceCache().remove(ctx.getId()); 379 } 380 catch(Exception e) 381 { 382 log.debug("Exception releasing context", e); 383 } 384 break; 385 } 386 } 387 } 388 } 389 finally 390 { 391 if(didSetReadOnly) 393 { 394 ctx.setReadOnly(false); 395 } 396 } 397 } 398 399 protected class InstanceSynchronization 400 implements Synchronization 401 { 402 405 protected Transaction tx; 406 407 410 protected EntityEnterpriseContext ctx; 411 412 415 protected BeanLock lock; 416 417 420 InstanceSynchronization(Transaction tx, EntityEnterpriseContext ctx) 421 { 422 this.tx = tx; 423 this.ctx = ctx; 424 this.lock = container.getLockManager().getLock(ctx.getCacheKey()); 425 } 426 427 public void beforeCompletion() 428 { 429 } 431 432 public void afterCompletion(int status) 433 { 434 boolean trace = log.isTraceEnabled(); 435 436 ClassLoader oldCl = SecurityActions.getContextClassLoader(); 439 boolean setCl = !oldCl.equals(container.getClassLoader()); 440 if(setCl) 441 { 442 SecurityActions.setContextClassLoader(container.getClassLoader()); 443 } 444 445 int commitOption = ctx.isPassivateAfterCommit() ? 446 ConfigurationMetaData.C_COMMIT_OPTION : EntitySynchronizationInterceptor.this.commitOption; 447 448 lock.sync(); 449 ctx.hasTxSynchronization(false); 451 ctx.setTxAssociation(GlobalTxEntityMap.NONE); 452 ctx.setTransaction(null); 453 try 454 { 455 try 456 { 457 if(status == Status.STATUS_ROLLEDBACK) 459 { 460 container.getInstanceCache().remove(ctx.getCacheKey()); 462 } 463 else 464 { 465 switch(commitOption) 466 { 467 case ConfigurationMetaData.A_COMMIT_OPTION: 469 case ConfigurationMetaData.D_COMMIT_OPTION: 470 ctx.setValid(true); 472 break; 473 474 case ConfigurationMetaData.B_COMMIT_OPTION: 476 ctx.setValid(false); 478 break; 479 case ConfigurationMetaData.C_COMMIT_OPTION: 481 try 482 { 483 if(ctx.getId() != null) 487 { 488 container.getInstanceCache().remove(ctx.getId()); 489 container.getPersistenceManager().passivateEntity(ctx); 490 } 491 container.getInstancePool().free(ctx); 493 } 494 catch(Exception e) 495 { 496 log.debug("Exception releasing context", e); 497 } 498 break; 499 } 500 } 501 } 502 finally 503 { 504 if(trace) 505 log.trace("afterCompletion, clear tx for ctx=" + ctx + ", tx=" + tx); 506 lock.endTransaction(tx); 507 508 if(trace) 509 log.trace("afterCompletion, sent notify on TxLock for ctx=" + ctx); 510 } 511 } finally 513 { 514 lock.releaseSync(); 515 container.getLockManager().removeLockRef(lock.getId()); 516 if(setCl) 517 { 518 SecurityActions.setContextClassLoader(oldCl); 519 } 520 } 521 } 522 523 } 524 525 528 class ValidContextsRefresher extends TimerTask 529 { 530 public ValidContextsRefresher() 531 { 532 } 533 534 public void run() 535 { 536 if (container == null) 538 { 539 cancel(); 540 return; 541 } 542 543 if(log.isTraceEnabled()) 544 log.trace("Flushing the valid contexts " + container.getBeanMetaData().getEjbName()); 545 546 EntityCache cache = (EntityCache) container.getInstanceCache(); 547 try 548 { 549 if(cache != null) 550 cache.flush(); 551 } 552 catch (Throwable t) 553 { 554 log.debug("Ignored error while trying to flush() entity cache", t); 555 } 556 } 557 } 558 } 559 | Popular Tags |