1 23 package com.sun.ejb.containers; 24 25 import java.rmi.RemoteException ; 26 import java.io.IOException ; 27 import java.util.*; 28 import java.lang.reflect.Method ; 29 30 import javax.ejb.*; 31 import javax.transaction.*; 32 33 import com.sun.ejb.*; 34 import com.sun.ejb.spi.container.BeanStateSynchronization; 35 import com.sun.enterprise.*; 36 import com.sun.enterprise.deployment.*; 37 import com.sun.enterprise.log.Log; 38 39 import java.util.logging.*; 40 import com.sun.ejb.containers.util.cache.EJBObjectCache; 41 import com.sun.ejb.containers.util.cache.FIFOEJBObjectCache; 42 import com.sun.ejb.containers.util.cache.UnboundedEJBObjectCache; 43 import com.sun.appserv.util.cache.Cache; 44 import com.sun.logging.*; 45 46 import com.sun.ejb.spi.distributed.DistributedEJBServiceFactory; 47 import com.sun.ejb.spi.distributed.DistributedReadOnlyBeanService; 48 import com.sun.ejb.spi.distributed.ReadOnlyBeanRefreshEventHandler; 49 import java.util.Timer ; 50 import java.util.TimerTask ; 51 52 53 60 61 public class ReadOnlyBeanContainer 62 extends EntityContainer 63 implements ReadOnlyBeanRefreshEventHandler 64 { 65 private static Logger _logger; 66 static { 67 _logger=LogDomains.getLogger(LogDomains.EJB_LOGGER); 68 } 69 70 private long refreshPeriodInMillis = 0; 71 72 private int beanLevelSequenceNum = 1; 76 77 private long beanLevelLastRefreshRequestedAt = 0; 79 80 81 private TimerTask refreshTask = null; 83 84 private EJBObjectCache robCache; 85 86 private DistributedReadOnlyBeanService distributedReadOnlyBeanService; 87 88 protected ReadOnlyBeanContainer(EjbDescriptor desc, ClassLoader loader) 89 throws Exception 90 { 91 super(desc, loader); 92 93 containerFactory = (ContainerFactoryImpl) 94 theSwitch.getContainerFactory(); 95 EjbEntityDescriptor ed = (EjbEntityDescriptor)desc; 96 refreshPeriodInMillis = 97 ed.getIASEjbExtraDescriptors().getRefreshPeriodInSeconds() * 1000; 98 99 if( refreshPeriodInMillis > 0 ) { 100 Timer timer = 101 ContainerFactoryImpl.getContainerService().getTimer(); 102 refreshTask = new RefreshTask(); 103 timer.scheduleAtFixedRate(refreshTask, refreshPeriodInMillis, 104 refreshPeriodInMillis); 105 } else { 106 refreshPeriodInMillis = 0; 107 } 108 109 long idleTimeoutInMillis = (cacheProp.cacheIdleTimeoutInSeconds <= 0) ? 111 -1 : (cacheProp.cacheIdleTimeoutInSeconds * 1000); 112 113 if( (cacheProp.maxCacheSize <= 0) && (idleTimeoutInMillis <= 0) ) { 114 robCache = new UnboundedEJBObjectCache(ejbDescriptor.getName()); 115 robCache.init(DEFAULT_CACHE_SIZE, cacheProp.numberOfVictimsToSelect, 116 0L, 1.0F, null); 117 } else { 118 int cacheSize = (cacheProp.maxCacheSize <= 0) ? 119 DEFAULT_CACHE_SIZE : cacheProp.maxCacheSize; 120 robCache = new FIFOEJBObjectCache(ejbDescriptor.getName()); 121 122 robCache.init(cacheSize, 123 cacheProp.numberOfVictimsToSelect, 124 idleTimeoutInMillis, 1.0F, null); 125 } 128 129 this.distributedReadOnlyBeanService = 130 DistributedEJBServiceFactory.getDistributedEJBService() 131 .getDistributedReadOnlyBeanService(); 132 this.distributedReadOnlyBeanService.addReadOnlyBeanRefreshEventHandler( 133 getContainerId(), getClassLoader(), this); 134 } 135 136 private void updateBeanLevelRefresh() { 137 138 beanLevelSequenceNum++; 139 beanLevelLastRefreshRequestedAt = System.currentTimeMillis(); 140 _logger.log(Level.FINE, "updating bean-level refresh for " + 141 " read-only bean " + ejbDescriptor.getName() + 142 " at " + new Date(beanLevelLastRefreshRequestedAt) + 143 " beanLevelSequenceNum = " + beanLevelSequenceNum); 144 } 145 146 protected void callEJBStore(EntityBean ejb, EntityContextImpl context) { 147 } 150 151 protected void callEJBLoad(EntityBean ejb, EntityContextImpl entityCtx) 152 throws Exception 153 { 154 ReadOnlyContextImpl context = (ReadOnlyContextImpl) entityCtx; 155 156 ReadOnlyBeanInfo robInfo = context.getReadOnlyBeanInfo(); 157 158 164 int pkLevelSequenceNum = 0; 165 166 synchronized(robInfo) { 167 168 int currentBeanLevelSequenceNum = beanLevelSequenceNum; 169 170 if( robInfo.beanLevelSequenceNum != currentBeanLevelSequenceNum) { 171 172 if( _logger.isLoggable(Level.FINE) ) { 173 _logger.log(Level.FINE, "REFRESH DUE TO BEAN-LEVEL UPDATE:" 174 + " Bean-level sequence num = " + 175 beanLevelSequenceNum + 176 robInfo + " current time is " + new Date()); 177 } 178 179 robInfo.refreshNeeded = true; 180 } 181 182 if (robInfo.refreshNeeded) { 185 186 if( _logger.isLoggable(Level.FINE) ) { 187 _logger.log(Level.FINE, " PK-LEVEL REFRESH : " 188 + robInfo + " current time is " + new Date()); 189 } 190 191 try { 192 193 if( isContainerManagedPers ) { 194 BeanStateSynchronization beanStateSynch = 195 (BeanStateSynchronization) ejb; 196 197 beanStateSynch.ejb__refresh(entityCtx.getPrimaryKey()); 198 199 if( _logger.isLoggable(Level.FINE) ) { 200 _logger.log(Level.FINE, " PK-LEVEL REFRESH DONE :" 201 + robInfo + " current time is " + new Date()); 202 } 203 204 } else { 205 206 if( ejb instanceof BeanStateSynchronization ) { 207 BeanStateSynchronization beanStateSynch = 210 (BeanStateSynchronization) ejb; 211 212 beanStateSynch.ejb__refresh 213 (entityCtx.getPrimaryKey()); 214 } 215 216 } 217 218 } finally { 219 robInfo.refreshNeeded = false; 221 } 222 223 225 updateAfterRefresh(robInfo); 226 } 227 228 pkLevelSequenceNum = robInfo.pkLevelSequenceNum; 229 230 } 232 if (transactionManager.getStatus() != Status.STATUS_NO_TRANSACTION) 238 { 239 callLoad(ejb, context, pkLevelSequenceNum, 246 System.currentTimeMillis()); 247 248 } else if( context.getPKLevelSequenceNum() != pkLevelSequenceNum ) { 249 250 callLoad(ejb, context, pkLevelSequenceNum, 253 System.currentTimeMillis()); 254 return; 255 } 256 } 257 258 private void callLoad(EntityBean ejb, EntityContextImpl entityCtx, 259 int pkLevelSequenceNum, 260 long currentTime) throws Exception { 261 262 ReadOnlyContextImpl context = (ReadOnlyContextImpl) entityCtx; 263 264 if( _logger.isLoggable(Level.FINE) ) { 265 _logger.log(Level.FINE, 266 "Calling ejbLoad for read-only bean " + 267 ejbDescriptor.getName() + " primary key " + 268 entityCtx.getPrimaryKey() + " at " + 269 new Date(currentTime)); 270 } 271 272 try { 273 context.setInEjbLoad(true); 274 ejb.ejbLoad(); 275 276 if( pkLevelSequenceNum > 0 ) { 277 context.setPKLevelSequenceNum(pkLevelSequenceNum); 279 } 280 281 context.setLastRefreshedAt(currentTime); 283 } finally { 284 context.setInEjbLoad(false); 285 } 286 287 } 288 289 protected void callEJBRemove(EntityBean ejb, EntityContextImpl context) 290 throws Exception 291 { 292 293 297 Object pk = context.getPrimaryKey(); 298 robCache.removeAll(pk); 299 300 } 301 302 public void undeploy() { 303 this.distributedReadOnlyBeanService.removeReadOnlyBeanRefreshEventHandler( 304 getContainerId()); 305 super.undeploy(); 306 307 if( refreshTask != null ) { 308 refreshTask.cancel(); 309 } 310 311 robCache.clear(); 312 } 313 314 void preInvokeNoTx(Invocation inv) { 318 EntityContextImpl context = (EntityContextImpl)inv.context; 319 320 if ( context.getState() == DESTROYED ) 321 return; 322 323 if ( !inv.invocationInfo.isCreateHomeFinder ) { 324 EntityBean e = (EntityBean)context.getEJB(); 326 try { 327 callEJBLoad(e, context); 328 } catch ( NoSuchEntityException ex ) { 329 _logger.log(Level.FINE, "Exception in preInvokeNoTx()", ex); 330 forceDestroyBean(context); 332 333 throw new NoSuchObjectLocalException( 334 "NoSuchEntityException thrown by ejbLoad, " + 335 "EJB instance discarded"); 336 } catch ( Exception ex ) { 337 forceDestroyBean(context); 339 340 throw new EJBException(ex); 341 } 342 context.setNewlyActivated(false); 343 } 344 } 345 346 protected void afterNewlyActivated(EntityContextImpl context) { 347 ReadOnlyBeanInfo robInfo = addToCache(context.getPrimaryKey(), true); 349 350 ReadOnlyContextImpl readOnlyContext = (ReadOnlyContextImpl) context; 353 readOnlyContext.setReadOnlyBeanInfo(robInfo); 354 } 355 356 protected void addPooledEJB(EntityContextImpl ctx) { 357 try { 358 ReadOnlyContextImpl readOnlyCtx = (ReadOnlyContextImpl)ctx; 359 if( readOnlyCtx.getReadOnlyBeanInfo() != null ) { 360 361 readOnlyCtx.setReadOnlyBeanInfo(null); 362 363 robCache.remove(ctx.getPrimaryKey(), true); 364 } 365 } catch (Exception ex) { 366 367 _logger.log(Level.SEVERE, "ejb.addPooledEJB", ex); 368 EJBException ejbEx = new EJBException(); 369 ejbEx.initCause(ex); 370 throw ejbEx; 371 372 } finally { 373 super.addPooledEJB(ctx); 374 } 375 } 376 377 protected void forceDestroyBean(EJBContextImpl context) { 378 379 try { 380 ReadOnlyContextImpl readOnlyCtx = (ReadOnlyContextImpl) context; 381 if( readOnlyCtx.getReadOnlyBeanInfo() != null ) { 382 383 readOnlyCtx.setReadOnlyBeanInfo(null); 384 385 robCache.remove(readOnlyCtx.getPrimaryKey(), true); 386 } 387 388 } catch (Exception ex) { 389 390 _logger.log(Level.SEVERE, "ejb.forceDestroyBean", ex); 391 EJBException ejbEx = new EJBException(); 392 ejbEx.initCause(ex); 393 throw ejbEx; 394 395 } finally { 396 super.forceDestroyBean(context); 397 } 398 } 399 400 public void preInvoke(Invocation inv) { 401 402 if( (inv.invocationInfo != null) && 410 inv.invocationInfo.startsWithCreate ) { 411 412 String msg = "Error for ejb " + ejbDescriptor.getName() + 413 ". create is not allowed for read-only entity beans"; 414 415 if( isContainerManagedPers ) { 416 424 throw new EJBException(msg); 425 426 } else { 427 CreateException ce = new CreateException(msg); 429 throw new PreInvokeException(ce); 430 } 431 432 } else { 433 super.preInvoke(inv); 434 } 435 } 436 437 protected void removeBean(EJBLocalRemoteObject ejbo, Method removeMethod, 438 boolean local) 439 throws RemoveException, EJBException, RemoteException 440 { 441 442 String msg = "Error for ejb " + ejbDescriptor.getName() + 443 ". remove is not allowed for read-only entity beans"; 444 445 if( isContainerManagedPers ) { 446 447 455 if (local) { 458 throw new EJBException(msg); 459 } else { 460 throw new RemoteException (msg); 461 } 462 463 } else { 464 } 470 } 471 472 protected void initializeHome() 473 throws Exception 474 { 475 super.initializeHome(); 476 477 if (isRemote) { 478 ((ReadOnlyEJBHomeImpl) this.ejbHomeImpl). 479 setReadOnlyBeanContainer(this); 480 } 481 482 if (isLocal) { 483 ReadOnlyEJBLocalHomeImpl readOnlyLocalHomeImpl = 484 (ReadOnlyEJBLocalHomeImpl) ejbLocalHomeImpl; 485 readOnlyLocalHomeImpl.setReadOnlyBeanContainer(this); 486 } 487 } 488 489 public void setRefreshFlag(Object primaryKey) { 490 491 try { 492 handleRefreshRequest(primaryKey); 493 } finally { 494 distributedReadOnlyBeanService.notifyRefresh( 495 getContainerId(), primaryKey); 496 } 497 } 498 499 public void handleRefreshRequest(Object primaryKey) { 500 ReadOnlyBeanInfo robInfo = (ReadOnlyBeanInfo) 505 robCache.get(primaryKey, false); 506 if( robInfo != null ) { 507 508 synchronized(robInfo) { 509 510 robInfo.refreshNeeded = true; 511 robInfo.lastRefreshRequestedAt = System.currentTimeMillis(); 512 513 if( _logger.isLoggable(Level.FINE) ) { 514 _logger.log(Level.FINE, 515 "Updating refresh time for read-only bean " + 516 ejbDescriptor.getName() + " primary key " + primaryKey 517 + " at " + new Date(robInfo.lastRefreshRequestedAt) + 518 " pkLevelSequenceNum = " + robInfo.pkLevelSequenceNum); 519 } 520 } 521 } else { 522 _logger.log(Level.FINE, 523 "Refresh event for unknown read-only bean PK = " + 524 primaryKey + " at " + new Date()); 525 } 526 } 527 528 531 void refreshAll() { 532 try { 533 handleRefreshAllRequest(); 534 } finally { 535 distributedReadOnlyBeanService.notifyRefreshAll(getContainerId()); 536 } 537 } 538 539 public void handleRefreshAllRequest() { 540 updateBeanLevelRefresh(); 541 } 542 543 protected EntityContextImpl createEntityContextInstance(EntityBean ejb, 544 EntityContainer entityContainer) 545 { 546 return new ReadOnlyContextImpl(ejb, entityContainer); 547 } 548 549 private ReadOnlyBeanInfo addToCache(Object primaryKey, boolean incrementRefCount) { 550 551 ReadOnlyBeanInfo robInfo = (ReadOnlyBeanInfo) 556 robCache.get(primaryKey, incrementRefCount); 557 558 if( robInfo == null ) { 559 560 564 ReadOnlyBeanInfo newRobInfo = new ReadOnlyBeanInfo(); 565 566 newRobInfo.primaryKey = primaryKey; 567 568 newRobInfo.beanLevelSequenceNum = -1; 572 newRobInfo.refreshNeeded = true; 573 574 newRobInfo.pkLevelSequenceNum = 1; 575 576 newRobInfo.lastRefreshRequestedAt = 0; 577 newRobInfo.lastRefreshedAt = 0; 578 579 if( ejbDescriptor.isLocalInterfacesSupported() ) { 589 newRobInfo.cachedEjbLocalObject = 590 getEJBLocalObjectForPrimaryKey(primaryKey); 591 } 592 if( ejbDescriptor.isRemoteInterfacesSupported() ) { 593 newRobInfo.cachedEjbObject = 594 getEJBObjectStub(primaryKey, null); 595 } 596 597 ReadOnlyBeanInfo otherRobInfo = (ReadOnlyBeanInfo) 598 robCache.put(primaryKey, newRobInfo, incrementRefCount); 599 600 robInfo = (otherRobInfo == null) ? newRobInfo : otherRobInfo; 604 } 605 606 return robInfo; 607 } 608 609 protected Object invokeFindByPrimaryKey(Method method, Invocation inv, 613 Object [] args) 614 throws Throwable 615 { 616 Object returnValue = null; 617 ReadOnlyBeanInfo robInfo = addToCache(args[0], false); 618 synchronized (robInfo) { 619 returnValue = inv.isLocal 620 ? robInfo.cachedEjbLocalObject : robInfo.cachedEjbObject; 621 622 if ( robInfo.refreshNeeded ) { 623 _logger.log(Level.FINE, "ReadOnlyBeanContainer calling ejb.ejbFindByPK... for pk=" + args[0]); 624 returnValue = super.invokeFindByPrimaryKey(method, inv, args); 625 robInfo.refreshNeeded = false; 626 627 updateAfterRefresh(robInfo); 630 631 } 632 } 633 634 return returnValue; 635 } 636 637 public Object postFind(Invocation inv, Object primaryKeys, 638 Object [] findParams) 639 throws FinderException 640 { 641 642 Object returnValue = super.postFind(inv, primaryKeys, findParams); 644 645 if( !inv.method.getName().equals("findByPrimaryKey") ) { 660 if ( primaryKeys instanceof Enumeration ) { 661 Enumeration e = (Enumeration) primaryKeys; 662 while ( e.hasMoreElements() ) { 663 Object primaryKey = e.nextElement(); 664 if( primaryKey != null ) { 665 updateRobInfoAfterFinder(primaryKey); 666 } 667 } 668 } else if ( primaryKeys instanceof Collection ) { 669 Collection c = (Collection)primaryKeys; 670 Iterator it = c.iterator(); 671 while ( it.hasNext() ) { 672 Object primaryKey = it.next(); 673 if( primaryKey != null ) { 674 updateRobInfoAfterFinder(primaryKey); 675 } 676 } 677 } else { 678 if( primaryKeys != null ) { 679 updateRobInfoAfterFinder(primaryKeys); 680 } 681 } 682 } 683 684 return returnValue; 685 } 686 687 private void updateRobInfoAfterFinder(Object primaryKey) { 688 ReadOnlyBeanInfo robInfo = addToCache(primaryKey, false); 689 synchronized (robInfo) { 690 if( robInfo.refreshNeeded ) { 691 robInfo.refreshNeeded = false; 692 updateAfterRefresh(robInfo); 693 } 694 } 695 } 696 697 private void updateAfterRefresh(ReadOnlyBeanInfo robInfo) { 700 robInfo.beanLevelSequenceNum = beanLevelSequenceNum; 701 robInfo.pkLevelSequenceNum++; 702 robInfo.lastRefreshedAt = System.currentTimeMillis(); 703 } 704 705 private class RefreshTask extends TimerTask { 706 707 public void run() { 708 updateBeanLevelRefresh(); 709 } 710 } 711 712 } 713 | Popular Tags |