1 45 package org.openejb.core.entity; 46 47 import java.util.HashMap ; 48 import java.util.Hashtable ; 49 import java.util.Properties ; 50 51 import javax.ejb.EntityBean ; 52 import javax.transaction.Transaction ; 53 54 import org.openejb.ApplicationException; 55 import org.openejb.OpenEJB; 56 import org.openejb.OpenEJBException; 57 import org.openejb.core.DeploymentInfo; 58 import org.openejb.core.EnvProps; 59 import org.openejb.core.Operations; 60 import org.openejb.core.ThreadContext; 61 import org.openejb.util.LinkedListStack; 62 import org.openejb.util.Logger; 63 import org.openejb.util.SafeProperties; 64 import org.openejb.util.SafeToolkit; 65 import org.openejb.util.Stack; 66 93 public class EntityInstanceManager { 94 95 96 protected int poolsize = 0; 97 100 protected EntityContainer container; 101 107 protected Hashtable txReadyPool = new Hashtable ( ); 108 112 protected HashMap poolMap = null; 113 114 public Logger logger = Logger.getInstance( "OpenEJB", "org.openejb.util.resources" ); 115 116 protected SafeToolkit toolkit = SafeToolkit.getToolkit("EntityInstanceManager"); 117 120 public EntityInstanceManager( ){ 121 } 122 123 public void init(EntityContainer myContainer, HashMap deployments, Properties props) 124 throws OpenEJBException{ 125 126 SafeProperties safeProps = toolkit.getSafeProperties(props); 127 poolsize = safeProps.getPropertyAsInt(EnvProps.IM_POOL_SIZE, 100); 128 container = myContainer; 129 130 poolMap = new HashMap (); java.util.Iterator iterator = deployments.values().iterator(); 132 while(iterator.hasNext()){ 133 poolMap.put(((DeploymentInfo)iterator.next()).getDeploymentID(),new LinkedListStack(poolsize/2)); 134 } 135 136 } 137 138 141 157 public EntityBean obtainInstance(ThreadContext callContext) 158 throws OpenEJBException{ 159 Transaction currentTx = null; 160 try{ 161 currentTx = OpenEJB.getTransactionManager().getTransaction(); 162 }catch(javax.transaction.SystemException se){ 163 logger.error("Transaction Manager getTransaction() failed.", se); 164 throw new org.openejb.SystemException("TransactionManager failure"); 165 } 166 167 Object primaryKey = callContext.getPrimaryKey(); if(currentTx != null && primaryKey != null){ Key key = new Key(currentTx, callContext.getDeploymentInfo().getDeploymentID(),primaryKey); 170 SyncronizationWrapper wrapper = (SyncronizationWrapper)txReadyPool.get(key); 171 172 if(wrapper != null){ 174 if( !wrapper.isAssociated()){ 184 throw new org.openejb.InvalidateReferenceException(new javax.ejb.NoSuchEntityException ("Entity not found: "+primaryKey)); 185 }else if(callContext.getCurrentOperation() == Operations.OP_REMOVE){ 186 191 wrapper.disassociate(); 192 } 193 194 if(wrapper.isAvailable()){ 195 return wrapper.getEntityBean(); 198 }else{ 199 org.openejb.core.DeploymentInfo depInfo = (org.openejb.core.DeploymentInfo)callContext.getDeploymentInfo(); 202 if(depInfo.isReentrant()){ 203 214 return wrapper.getEntityBean(); 215 }else 216 throw new org.openejb.ApplicationException(new java.rmi.RemoteException ("Attempted reentrant access. Bean is not reentrant")); 217 } 218 } 219 else{ 220 225 EntityBean bean = getPooledInstance(callContext); 226 wrapper = new SyncronizationWrapper(bean, key, false, callContext); 227 228 if(callContext.getCurrentOperation()== Operations.OP_REMOVE){ 229 237 wrapper.disassociate(); 238 } 239 240 try{ 241 currentTx.registerSynchronization(wrapper); 242 }catch(javax.transaction.SystemException se){ 243 logger.error("Transaction Manager registerSynchronization() failed.", se); 244 throw new org.openejb.SystemException(se); 245 }catch(javax.transaction.RollbackException re){ 246 throw new org.openejb.ApplicationException(new javax.transaction.TransactionRolledbackException (re.getMessage())); 247 } 248 loadingBean(bean, callContext); 249 byte orginalOperation = callContext.getCurrentOperation(); 250 callContext.setCurrentOperation(org.openejb.core.Operations.OP_LOAD); 251 try{ 252 bean.ejbLoad(); 253 }catch(Exception e){ 254 logger.error("Exception encountered during ejbLoad():", e); 255 throw new org.openejb.OpenEJBException(e); 257 }finally { 258 callContext.setCurrentOperation(orginalOperation); 259 } 260 txReadyPool.put(key, wrapper); 261 262 return bean; 263 } 264 }else{ 269 return getPooledInstance(callContext); 270 } 271 } 272 273 277 protected void loadingBean(javax.ejb.EntityBean bean, org.openejb.core.ThreadContext callContext) throws OpenEJBException { 278 } 279 280 protected void reusingBean(javax.ejb.EntityBean bean, org.openejb.core.ThreadContext callContext) throws OpenEJBException { 281 } 282 283 289 protected EntityBean getPooledInstance(ThreadContext callContext) 290 throws org.openejb.OpenEJBException{ 291 DeploymentInfo deploymentInfo = callContext.getDeploymentInfo(); 292 Stack methodReadyPool = (Stack)poolMap.get(deploymentInfo.getDeploymentID()); 293 if(methodReadyPool==null) 294 throw new org.openejb.SystemException("Invalid deployment id "+deploymentInfo.getDeploymentID()+" for this container"); 295 296 EntityBean bean = (EntityBean )methodReadyPool.pop(); 297 if(bean == null){ 298 try{ 299 bean = (EntityBean )deploymentInfo.getBeanClass().newInstance(); 300 }catch(Exception e){ 301 logger.error("Bean instantiation failed for class "+deploymentInfo.getBeanClass(), e); 302 throw new org.openejb.SystemException(e); 303 } 304 308 byte currentOp = callContext.getCurrentOperation(); 309 callContext.setCurrentOperation(org.openejb.core.Operations.OP_SET_CONTEXT); 310 311 try{ 312 322 bean.setEntityContext((javax.ejb.EntityContext )callContext.getDeploymentInfo().getEJBContext()); 323 }catch(java.lang.Exception e){ 324 329 logger.error("Bean callback method failed ", e); 330 throw new org.openejb.ApplicationException(e); 331 }finally{ 332 callContext.setCurrentOperation(currentOp); 333 } 334 } else { 335 reusingBean(bean, callContext); 336 } 337 338 if( ( callContext.getCurrentOperation()== org.openejb.core.Operations.OP_BUSINESS) || 339 ( callContext.getCurrentOperation()== org.openejb.core.Operations.OP_REMOVE ) ) 340 { 341 350 byte currentOp = callContext.getCurrentOperation(); 351 352 callContext.setCurrentOperation(org.openejb.core.Operations.OP_ACTIVATE); 353 try{ 354 360 bean.ejbActivate(); 361 }catch(Throwable e){ 362 logger.error("Encountered exception during call to ejbActivate()", e); 363 try{ 364 Transaction tx = OpenEJB.getTransactionManager().getTransaction(); 365 if(tx!=null){ 366 tx.setRollbackOnly(); 367 throw new ApplicationException(new javax.transaction.TransactionRolledbackException ("Reflection exception thrown while attempting to call ejbActivate() on the instance. Exception message = "+e.getMessage())); 368 } 369 }catch(javax.transaction.SystemException se){ 370 logger.error("Transaction Manager getTransaction() failed.", se); 371 throw new org.openejb.SystemException(se); 372 } 373 throw new ApplicationException(new java.rmi.RemoteException ("Exception thrown while attempting to call ejbActivate() on the instance. Exception message = "+e.getMessage())); 374 }finally{ 375 callContext.setCurrentOperation(currentOp); 376 } 377 378 } 379 return bean; 380 } 381 389 public void poolInstance(ThreadContext callContext,EntityBean bean) 390 throws OpenEJBException{ 391 if(bean==null) { 392 return; 394 } 395 Object primaryKey = callContext.getPrimaryKey(); Transaction currentTx = null; 397 try{ 398 currentTx = OpenEJB.getTransactionManager().getTransaction(); 399 }catch(javax.transaction.SystemException se){ 400 logger.error("Transaction Manager getTransaction() failed.", se); 401 throw new org.openejb.SystemException("TransactionManager failure"); 402 } 403 if(currentTx != null && primaryKey != null){ Key key = new Key(currentTx, callContext.getDeploymentInfo().getDeploymentID(),primaryKey); 405 SyncronizationWrapper wrapper = (SyncronizationWrapper)txReadyPool.get(key); 406 if(wrapper != null){ 407 if(callContext.getCurrentOperation()== Operations.OP_REMOVE){ 408 414 wrapper.disassociate(); 415 419 Stack methodReadyPool = (Stack)poolMap.get(callContext.getDeploymentInfo().getDeploymentID()); 420 methodReadyPool.push(bean); 421 }else 422 wrapper.setEntityBean(bean); 423 }else{ 424 430 431 wrapper = new SyncronizationWrapper(bean, key, true, callContext); 432 433 try{ 434 currentTx.registerSynchronization(wrapper); 435 }catch(javax.transaction.SystemException se){ 436 logger.error("Transaction Manager registerSynchronization() failed.", se); 437 throw new org.openejb.SystemException(se); 438 }catch(javax.transaction.RollbackException re){ 439 throw new org.openejb.ApplicationException(new javax.transaction.TransactionRolledbackException (re.getMessage())); 440 } 441 442 txReadyPool.put(key, wrapper); 443 } 444 }else{ 445 449 450 if(primaryKey !=null && callContext.getCurrentOperation()!= Operations.OP_REMOVE){ 451 457 byte currentOp = callContext.getCurrentOperation(); 458 459 callContext.setCurrentOperation(org.openejb.core.Operations.OP_PASSIVATE); 460 461 462 try{ 463 469 bean.ejbPassivate(); 470 }catch(Throwable e){ 471 try{ 472 Transaction tx = OpenEJB.getTransactionManager().getTransaction(); 473 if(tx!=null){ 474 tx.setRollbackOnly(); 475 throw new ApplicationException(new javax.transaction.TransactionRolledbackException ("Reflection exception thrown while attempting to call ejbPassivate() on the instance. Exception message = "+e.getMessage())); 476 } 477 }catch(javax.transaction.SystemException se){ 478 logger.error("Transaction Manager getTransaction() failed.", se); 479 throw new org.openejb.SystemException(se); 480 } 481 throw new ApplicationException(new java.rmi.RemoteException ("Reflection exception thrown while attempting to call ejbPassivate() on the instance. Exception message = "+e.getMessage())); 482 }finally{ 483 callContext.setCurrentOperation(currentOp); 484 } 485 } 486 487 492 Stack methodReadyPool = (Stack)poolMap.get(callContext.getDeploymentInfo().getDeploymentID()); 493 methodReadyPool.push(bean); 494 } 495 496 497 } 498 499 507 public void freeInstance(ThreadContext callContext, EntityBean bean) 508 throws org.openejb.SystemException{ 509 510 discardInstance(callContext, bean); 511 512 byte currentOp = callContext.getCurrentOperation(); 513 callContext.setCurrentOperation(org.openejb.core.Operations.OP_UNSET_CONTEXT); 514 515 try{ 516 526 bean.unsetEntityContext(); 527 }catch(java.lang.Exception e){ 528 533 logger.info(getClass().getName()+".freeInstance: ignoring exception "+e+" on bean instance "+bean); 536 }finally{ 537 callContext.setCurrentOperation(currentOp); 538 } 539 540 541 } 542 543 554 public void discardInstance(ThreadContext callContext, EntityBean bean) 555 throws org.openejb.SystemException{ 556 Transaction currentTx = null; 557 try{ 558 currentTx = OpenEJB.getTransactionManager().getTransaction(); 559 }catch(javax.transaction.SystemException se){ 560 logger.error("Transaction Manager getTransaction() failed.", se); 561 throw new org.openejb.SystemException("TransactionManager failure"); 562 } 563 if(currentTx != null){ 564 if ( callContext.getPrimaryKey() == null ) 565 return; 566 Key key = new Key(currentTx, callContext.getDeploymentInfo().getDeploymentID(),callContext.getPrimaryKey()); 569 570 576 SyncronizationWrapper wrapper = (SyncronizationWrapper)txReadyPool.remove(key); 577 578 if(wrapper != null){ 579 591 wrapper.disassociate(); 592 } 593 } 594 } 595 596 601 public static class Key { 602 private final Object deploymentID, primaryKey; 603 private final Transaction transaction; 604 605 public Key(Transaction tx, Object depID, Object prKey){ 606 if(tx==null || depID==null || prKey==null) { 607 throw new IllegalArgumentException (); 608 } 609 transaction = tx; 610 deploymentID = depID; 611 primaryKey = prKey; 612 } 613 public Object getPK() 614 { 615 return primaryKey; 616 } 617 public int hashCode( ){ 618 return transaction.hashCode()^deploymentID.hashCode()^primaryKey.hashCode(); 619 } 620 public boolean equals(Object other){ 621 if(other != null && other.getClass() == EntityInstanceManager.Key.class){ 622 Key otherKey = (Key)other; 623 if(otherKey.transaction.equals(transaction) && otherKey.deploymentID.equals(deploymentID) && otherKey.primaryKey.equals(primaryKey)) 624 return true; 625 } 626 return false; 627 } 628 } 629 630 637 protected class SyncronizationWrapper 638 implements javax.transaction.Synchronization { 639 private EntityBean bean; 640 645 private boolean isAvailable; 646 private boolean isAssociated; 647 private final ThreadContext context; 648 private final Key myIndex; 649 650 public SyncronizationWrapper(EntityBean ebean, Key key, boolean available, ThreadContext ctx) throws OpenEJBException{ 651 if(ebean==null || ctx==null || key==null) { 652 throw new IllegalArgumentException (); 653 } 654 bean = ebean; 655 isAvailable = available; 656 myIndex =key; 657 isAssociated=true; 658 try{ 659 context = (ThreadContext) ctx.clone(); 660 }catch(CloneNotSupportedException e) { 661 logger.error("Thread context class "+ctx.getClass()+" doesn't implement the Cloneable interface!", e); 662 throw new OpenEJBException("Thread context class "+ctx.getClass()+" doesn't implement the Cloneable interface!"); 663 } 664 } 665 public void disassociate( ){ 666 isAssociated = false; 667 } 668 public boolean isAssociated(){ 669 return isAssociated; 670 } 671 public synchronized boolean isAvailable(){ 672 return isAvailable; 673 } 674 public void setEntityBean(EntityBean ebean){ 675 isAvailable = true; 676 bean = ebean; 677 } 678 public EntityBean getEntityBean(){ 679 isAvailable = false; 680 return bean; 681 } 682 public void beforeCompletion(){ 683 if(isAssociated){ 684 ThreadContext currentContext = ThreadContext.getThreadContext(); 687 ThreadContext.setThreadContext(context); 688 byte orginalOperation = context.getCurrentOperation(); 689 context.setCurrentOperation(org.openejb.core.Operations.OP_STORE); 690 try{ 691 bean.ejbStore(); 692 }catch(Exception re){ 693 logger.error("Exception occured during ejbStore()", re); 694 javax.transaction.TransactionManager txmgr = OpenEJB.getTransactionManager(); 695 try{ 696 txmgr.setRollbackOnly(); 697 }catch(javax.transaction.SystemException se){ 698 logger.error("Transaction manager reported error during setRollbackOnly()", se); 699 } 700 701 }finally { 702 ThreadContext.setThreadContext(currentContext); 704 } 705 } 706 } 707 public void afterCompletion(int status){ 708 txReadyPool.remove(myIndex); 709 } 710 711 } 712 } 713 714 | Popular Tags |