EntityContainerpublic class EntityContainer extends BaseContainer implements com.sun.ejb.spi.stats.EntityBeanStatsProvider, com.sun.appserv.util.cache.CacheListenerThis class implements the Container interface for EntityBeans.
It is responsible for instance & lifecycle management for BMP & CMP
EntityBeans.
The EntityContainer implements option B of the commit-time options
described in the EJB2.0 spec section 10.5.9
It also implements optimistic concurrency (i.e. multiple non-exclusive
bean instances per primary key) when there are multiple concurrent
transactions on a EntityBean.
The following sequence of actions happens for the EntityContainer,
for each EJB lifecycle stage (note: getEJBObject, getContext,
releaseContext, preInvokeTx, postInvokeTx are called from BaseContainer).
1. EJB Creation
homeImpl.create, container.getContext,
container.preInvokeTx, ejb.ejbCreate, container.postCreate,
ejb.ejbPostCreate, container.postInvokeTx, container.releaseContext
2. EJB Finding
homeImpl.find---, container.getContext, container.preInvokeTx,
ejb.ejbFind---, container.postFind, container.postInvokeTx,
container.releaseContext
3. EJB Invocation
container.getEJBObject, ejbObject.someMethod, container.getContext,
container.preInvokeTx, ejb.someMethod, container.postInvokeTx,
container.releaseContext
State Management: The EntityContainer manages collections of EJBs
in different states.
The 5 states of an EntityBean (an EJB can be in only 1 state at a time):
- 1. POOLED : does not have identity. EJBs in the POOLED state are
all identical, hence are maintained in a java.util.Vector,
whose size is maintained below a HIGH_WATER_MARK (currently 100).
- 2. READY : ready for invocations, no transaction in progress.
EJBs in the READY state are associated with a primary key.
To enhance reuse of EJB instances, only one READY
EJB per primary key is stored. READY EJBs are managed by the
ejbstore/EntityStore class. READY EJBs are looked up using a key consisting
of the primary key and a null transaction context.
- 3. INVOKING : processing an invocation.
EJBs in the INVOKING state are not stored anywhere. Before transitioning
from READY or INCOMPLETE_TX to INVOKING, the EJB is removed from the
EntityStore.
- 4. INCOMPLETE_TX : ready for invocations, transaction in progress.
EJBs in the INCOMPLETE_TX state are associated with a primary key.
INCOMPLETE_TX EJBs are managed by the ejbstore/EntityStore class.
INCOMPLETE_TX EJBs are looked up using a composite key consisting
of the primary key and the transaction context.
- 5. DESTROYED : does not exist.
All READY bean instances are stored in the readyStore.
All INCOMPLETE_TX bean instances are stored in the ActiveTxCache.
Beans in the READY state are stored with key = ejbObject.
Beans in the INCOMPLETE_TX state are stored with key = ejbObject+Tx.
Instances in INVOKING state which have transactions associated
with them are also in ActiveTxCache.
All POOLED instances are stored in the pooledEJBs vector.
Note on locking order: if both ready/ActiveTxCache and context are to be
locked, always acquire the context lock first, then the Store lock.
Note on locking order: if both ready/ActiveTxCache and ejbObject need
locks, always acquire the ejbObject lock first, then the Store lock. |
Fields Summary |
---|
protected static final Logger | _logger | private ThreadLocal | ejbServant | protected static final com.sun.enterprise.util.LocalStringManagerImpl | localStrings | static final int | POOLED | static final int | READY | static final int | INVOKING | static final int | INCOMPLETE_TX | static final int | DESTROYED | protected static final int | HIGH_WATER_MARK | private static final int | DEFAULT_TX_CACHE_BUCKETS | protected com.sun.ejb.containers.util.cache.EJBObjectCache | ejbObjectStore | protected com.sun.ejb.containers.util.cache.EJBObjectCache | ejbLocalObjectStore | protected Stack | passivationCandidates | protected com.sun.appserv.util.cache.Cache | readyStore | protected AbstractPool | entityCtxPool | protected boolean | isReentrant | protected boolean | isContainerManagedPers | protected final float | DEFAULT_LOAD_FACTOR | protected final int | DEFAULT_CACHE_SIZE | protected int | _maxBuckets | protected com.sun.enterprise.deployment.runtime.IASEjbExtraDescriptors | iased | protected com.sun.enterprise.deployment.runtime.BeanCacheDescriptor | beanCacheDes | protected com.sun.enterprise.deployment.runtime.BeanPoolDescriptor | beanPoolDes | protected Server | svr | protected Config | cfg | protected EjbContainer | ejbContainer | boolean | largeCache | CacheProperties | cacheProp | PoolProperties | poolProp | Object | asyncTaskSemaphore | boolean | addedASyncTask | protected IdleBeansPassivator | idleEJBObjectPassivator | protected IdleBeansPassivator | idleLocalEJBObjectPassivator | protected boolean | defaultCacheEJBO | IdleBeansPassivator | idleBeansPassivator | boolean | timerValid | long | idleTimeout | protected int | ejboRemoved | protected int | totalPassivations | protected int | totalPassivationErrors | private EntityCacheStatsProvider | cacheStatsProvider |
Constructors Summary |
---|
protected EntityContainer(EjbDescriptor desc, ClassLoader loader)This constructor is called from the JarManager when a Jar is deployed.
_logger.log(Level.FINE," Loading Entitycontainer...");
super(desc, loader);
EjbEntityDescriptor ed = (EjbEntityDescriptor)desc;
isReentrant = ed.isReentrant();
if ( ed.getPersistenceType().equals(
EjbEntityDescriptor.BEAN_PERSISTENCE) ) {
isContainerManagedPers = false;
} else {
isContainerManagedPers = true;
}
iased = ed.getIASEjbExtraDescriptors();
if( iased != null) {
beanCacheDes = iased.getBeanCache();
beanPoolDes = iased.getBeanPool();
}
try {
ServerContext sc = ApplicationServer.getServerContext();
//ROB: config changes
//svr = ServerBeansFactory.getServerBean(sc.getConfigContext());
cfg = ServerBeansFactory.getConfigBean(sc.getConfigContext());
} catch (ConfigException ex) {
_logger.log(Level.WARNING, "ejb.entitycontainer_exception", ex);
}
//ROB: config changes
//ejbContainer = svr.getEjbContainer();
ejbContainer = cfg.getEjbContainer();
super.setMonitorOn(ejbContainer.isMonitoringEnabled());
createCaches();
super.createCallFlowAgent(
isContainerManagedPers ? ComponentType.CMP : ComponentType.BMP);
_logger.log(Level.FINE,"[EntityContainer] Created EntityContainer: "
+ logParams[0]);
|
Methods Summary |
---|
protected ComponentContext | _getContext(Invocation inv)Called from BaseContainer.preInvoke which is called from the EJBObject
for local and remote invocations, and from the EJBHome for create/find.
String name = inv.method.getName();
if ( inv.invocationInfo.isCreateHomeFinder ) {
// create*, find*, home methods
// Note: even though CMP finders dont need an instance,
// we still return a pooled instance, so that the Tx demarcation
// in BaseContainer.pre+postInvoke can work.
// get any pooled EJB
EntityContextImpl context = getPooledEJB();
// we're sure that no concurrent thread can be using this
// context, so no need to synchronize.
context.setState(INVOKING);
if ( inv.invocationInfo.startsWithCreate )
preCreate(inv, context);
else if ( inv.invocationInfo.startsWithFind )
preFind(inv, context);
context.setLastTransactionStatus(-1);
context.incrementCalls();
return context;
}
// If we came here, it means this is a business method
// and there is an EJBObject/LocalObject.
// If we would invoke the EJB with the client's Tx,
// try to get an EJB with that incomplete Tx.
EntityContextImpl context = null;
if ( willInvokeWithClientTx(inv) )
context = getEJBWithIncompleteTx(inv);
if ( context == null )
context = getReadyEJB(inv);
synchronized ( context ) {
if ( context.getState() == INVOKING && !isReentrant )
throw new EJBException(
"EJB is already executing another request");
if (context.getState() == POOLED ||
context.getState() == DESTROYED) {
// somehow a concurrent thread must have changed state.
// this is an internal error.
throw new EJBException("Internal error: unknown EJB state");
}
context.setState(INVOKING);
}
context.setLastTransactionStatus(-1);
context.incrementCalls();
// A business method may modify the bean's state
context.setDirty(true);
return context;
| protected EntityContextImpl | activateEJBFromPool(java.lang.Object primaryKey, Invocation inv)Called from getContext and getEJBWithIncompleteTx
Get an EJB in the ready state (i.e. which is not doing any
invocations and doesnt have any incomplete Tx), for the
ejbObject provided in the Invocation.
Concurrent invocations should get *different* instances.
EntityContextImpl context = null;
// get a pooled EJB and activate it.
context = getPooledEJB();
// we're sure that no concurrent thread can be using this
// context, so no need to synchronize.
// set EJBObject/LocalObject for the context
if ( inv.isLocal ) {
EJBLocalObjectImpl localObjImpl =
internalGetEJBLocalObjectImpl(primaryKey, true);
inv.ejbObject = localObjImpl;
context.setEJBLocalObjectImpl(localObjImpl);
// No need to create/set EJBObject if this EJB isRemote too.
// This saves remote object creation overhead.
// The EJBObject and stub will get created lazily if needed
// when EntityContext.getEJBObjectImpl is called.
} else { // remote invocation
EJBObjectImpl ejbObjImpl =
internalGetEJBObjectImpl(primaryKey, null, true);
inv.ejbObject = ejbObjImpl;
context.setEJBObjectImpl(ejbObjImpl);
context.setEJBStub((EJBObject)ejbObjImpl.getStub());
if ( isLocal ) {
// Create EJBLocalObject so EntityContext methods work
context.setEJBLocalObjectImpl(
internalGetEJBLocalObjectImpl(primaryKey, true));
}
}
context.setState(READY);
EntityBean ejb = (EntityBean)context.getEJB();
Invocation inv2 = new Invocation(ejb, this, context);
inv2.method = ejbActivateMethod;
invocationManager.preInvoke(inv2);
try {
ejb.ejbActivate();
// Note: ejbLoad will be called during preInvokeTx
// since this EJB instance is being associated with
// a Tx for the first time.
} catch ( Exception ex ) {
// Error during ejbActivate, discard bean: EJB2.0 18.3.3
forceDestroyBean(context);
throw new EJBException(ex);
} finally {
invocationManager.postInvoke(inv2);
}
context.setNewlyActivated(true);
//recycler.initSoftRef(context);
afterNewlyActivated(context);
return context;
| private void | addIncompleteTxEJB(EntityContextImpl context)Called only from afterBegin.
This EJB is invoked either with client's tx (in which case
it would already be in table), or with new tx (in which case
it would not be in table).
J2EETransaction current = (J2EETransaction) context.getTransaction();
if ( current == null ) {
return;
}
if ( (context.getEJBObjectImpl() == null) &&
(context.getEJBLocalObjectImpl() == null) ) {
return;
}
// Its ok to add this context without checking if its already there.
ActiveTxCache activeTxCache = (ActiveTxCache) current.getActiveTxCache();
if (activeTxCache == null) {
activeTxCache = new ActiveTxCache(DEFAULT_TX_CACHE_BUCKETS);
current.setActiveTxCache(activeTxCache);
}
activeTxCache.add(context);
Vector beans = containerFactory.getBeans(current);
beans.add(context);
| protected void | addPooledEJB(EntityContextImpl context)
if ( context.getState() == POOLED ) {
return;
}
// we're sure that no concurrent thread can be using this
// context, so no need to synchronize.
context.setEJBLocalObjectImpl(null);
context.setEJBObjectImpl(null);
context.setEJBStub(null);
context.setState(POOLED);
context.clearCachedPrimaryKey();
//context.cacheEntry = null;
entityCtxPool.returnObject(context);
| protected void | addReadyEJB(EntityContextImpl context)
// add to the cache (can have multiple instances of beans per key)
Object primaryKey = context.getPrimaryKey();
context.setState(READY);
readyStore.add(primaryKey, context);
| void | afterBegin(EJBContextImpl ctx)
// Note: EntityBeans are not allowed to be TX_BEAN_MANAGED
if ( ctx.getState() == DESTROYED )
return;
EntityContextImpl context = (EntityContextImpl)ctx;
if ( context.getEJBObjectImpl() != null
|| context.getEJBLocalObjectImpl() != null ) {
// ejbLoad needed only for business methods and removes
// Add EJB to INCOMPLETE_TX table so that concurrent/loopback
// invocations will be correctly handled
if ( context.getTransaction() != null ) {
addIncompleteTxEJB(context);
}
// need to call ejbLoad since there can be more than
// one active EJB instance per primaryKey. (Option B in 9.11.5).
EntityBean e = (EntityBean)context.getEJB();
try {
callEJBLoad(e, context, true);
} catch ( NoSuchEntityException ex ) {
_logger.log(Level.FINE, "Exception in afterBegin()", ex);
// Error during ejbLoad, so discard bean: EJB2.0 18.3.3
forceDestroyBean(context);
throw new NoSuchObjectLocalException(
"NoSuchEntityException thrown by ejbLoad, EJB instance discarded", ex);
} catch ( Exception ex ) {
// Error during ejbLoad, so discard bean: EJB2.0 18.3.3
forceDestroyBean(context);
throw new EJBException(ex);
}
context.setNewlyActivated(false);
}
| void | afterCompletion(EJBContextImpl ctx, int status)
if ( ctx.getState() == DESTROYED ) {
return;
}
if (super.isUndeployed()) {
transactionManager.ejbDestroyed(ctx);
return;
}
EntityContextImpl context = (EntityContextImpl)ctx;
EJBLocalRemoteObject ejbObjImpl = context.getEJBObjectImpl();
EJBLocalRemoteObject ejbLocalObjImpl = context.getEJBLocalObjectImpl();
// home methods, finders and remove dont need this
if ( ((ejbObjImpl != null) && !ejbObjImpl.isRemoved())
|| ((ejbLocalObjImpl != null) && !ejbLocalObjImpl.isRemoved()) ) {
// Remove bean from ActiveTxCache table if its there.
// No need to remove it from txBeanTable because the table
// gets updated in ContainerFactoryImpl.removeContainerSync.
//removeIncompleteTxEJB(context, false);
context.setTransaction(null);
context.setLastTransactionStatus(status);
context.setCascadeDeleteAfterSuperEJBRemove(false);
context.setCascadeDeleteBeforeEJBRemove(false);
// Move context to ready state if tx commited, else to pooled state
if ( context.getState() != INVOKING ) {
if ( (status == Status.STATUS_COMMITTED)
|| (status == Status.STATUS_NO_TRANSACTION) ) {
addReadyEJB(context);
} else {
passivateAndPoolEJB(context);
}
}
} else if ((ejbObjImpl == null) && (ejbLocalObjImpl == null)) {
// This happens if an ejbcreate has an exception, in that case
// we remove bean from ActiveTxCache table if its there.
// and return it to the pool
//removeIncompleteTxEJB(context, false);
context.setTransaction(null);
context.setLastTransactionStatus(status);
context.setCascadeDeleteAfterSuperEJBRemove(false);
context.setCascadeDeleteBeforeEJBRemove(false);
if ( context.getState() != INVOKING ) {
addPooledEJB(context);
}
} else if ( ((ejbObjImpl != null) && ejbObjImpl.isRemoved())
|| ((ejbLocalObjImpl != null) && ejbLocalObjImpl.isRemoved()) )
{
//removeIncompleteTxEJB(context, false);
context.setTransaction(null);
context.setLastTransactionStatus(status);
if (context.getState() == INCOMPLETE_TX) {
addPooledEJB(context);
}
}
| protected void | afterNewlyActivated(EntityContextImpl context)
//Noop for EntityContainer
| private static void | appendStat(java.lang.StringBuffer sbuf, java.lang.String header, java.util.Map map)
sbuf.append("\n\t[").append(header).append(": ");
if (map != null) {
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
String name = (String)iter.next();
sbuf.append(name).append("=").append(map.get(name))
.append("; ");
}
} else {
sbuf.append("NONE");
}
sbuf.append("]");
| public void | appendStats(java.lang.StringBuffer sbuf)
sbuf.append("\nEntityContainer: ")
.append("CreateCount=").append(statCreateCount).append("; ")
.append("RemoveCount=").append(statRemoveCount).append("; ")
.append("PassQSize=")
.append(passivationCandidates.size()).append("]");
Map stats = null;
if (readyStore != null) {
stats = readyStore.getStats();
}
appendStat(sbuf, "ReadyStore", stats);
appendStat(sbuf, "EJBObjectStore", ejbObjectStore.getStats());
appendStat(sbuf, "EJBLocalObjectStore",ejbLocalObjectStore.getStats());
| void | beforeCompletion(EJBContextImpl ctx)
if ( ctx.getState() == DESTROYED ) {
return;
}
EntityContextImpl context = (EntityContextImpl)ctx;
EJBLocalRemoteObject ejbObjImpl = context.getEJBObjectImpl();
EJBLocalRemoteObject ejbLocalObjImpl = context.getEJBLocalObjectImpl();
// Call ejbStore as required by diagram in EJB2.0 section 10.9.4
// home methods, finders and remove dont need ejbStore
if ( ((ejbObjImpl != null) && !ejbObjImpl.isRemoved())
|| ((ejbLocalObjImpl != null) && !ejbLocalObjImpl.isRemoved()) ) {
if ( context.isDirty() ) {
enlistResourcesAndStore(context);
}
}
| protected void | callEJBLoad(EntityBean ejb, EntityContextImpl context, boolean activeTx)
try {
context.setInEjbLoad(true);
ejb.ejbLoad();
// Note: no need to do context.setDirty(false) because ejbLoad is
// called immediately before a business method.
} catch(Exception e) {
throw e;
} finally {
context.setInEjbLoad(false);
}
| protected void | callEJBRemove(EntityBean ejb, EntityContextImpl context)
Exception exc = null;
try {
context.setInEjbRemove(true);
ejb.ejbRemove();
} catch ( Exception ex ) {
exc = ex;
throw ex;
} finally {
context.setInEjbRemove(false);
context.setDirty(false); // bean is removed so doesnt need ejbStore
if ( AppVerification.doInstrument() ) {
AppVerification.getInstrumentLogger().doInstrumentForEjb(
ejbDescriptor, ejbRemoveMethod, exc);
}
}
| protected void | callEJBStore(EntityBean ejb, EntityContextImpl context)
try {
context.setInEjbStore(true);
ejb.ejbStore();
} finally {
context.setInEjbStore(false);
context.setDirty(false); // bean's state is in sync with DB
}
| public void | cancelTimerTasks()cancel a timer task to trim timed out entries in the cache.
timerValid = false;
if (idleBeansPassivator != null) {
try {
idleBeansPassivator.cancel();
idleBeansPassivator.cache = null;
} catch (Exception e) {
_logger.log(Level.FINE, "[EntityContainer] cancelTimerTask: " +
e);
}
}
if (idleEJBObjectPassivator != null) {
try {
idleEJBObjectPassivator.cancel();
idleEJBObjectPassivator.cache = null;
} catch (Exception e) {
_logger.log(Level.FINE, "[EntityContainer] cancelTimerTask: " +
e);
}
}
if (idleLocalEJBObjectPassivator != null) {
try {
idleLocalEJBObjectPassivator.cancel();
idleLocalEJBObjectPassivator.cache = null;
} catch (Exception e) {
_logger.log(Level.FINE, "[EntityContainer] cancelTimerTask: " +
e);
}
}
this.idleEJBObjectPassivator = null;
this.idleLocalEJBObjectPassivator = null;
this.idleBeansPassivator = null;
| void | checkExists(EJBLocalRemoteObject ejbObj)Check if the given EJBObject/LocalObject has been removed.
Called before executing non-business methods of EJBLocalObject.
// Need to call ejbLoad to see if persistent state is removed.
// However, the non-business methods dont have a transaction attribute.
// So do nothing for now.
| protected void | checkUnfinishedTx(javax.transaction.Transaction prevTx, Invocation inv)
try {
if ( (prevTx != null) &&
prevTx.getStatus() != Status.STATUS_NO_TRANSACTION ) {
// An unfinished tx exists for the bean.
// so we cannot invoke the bean with no Tx or a new Tx.
throw new IllegalStateException(
"Bean is associated with a different unfinished transaction");
}
} catch (SystemException ex) {
throw new EJBException(ex);
}
| private void | createCaches()
cacheProp = new CacheProperties();
int cacheSize = cacheProp.maxCacheSize;
int numberOfVictimsToSelect = cacheProp.numberOfVictimsToSelect;
float loadFactor = DEFAULT_LOAD_FACTOR;
idleTimeout = cacheProp.cacheIdleTimeoutInSeconds * 1000;
createReadyStore(cacheSize, numberOfVictimsToSelect, loadFactor,
idleTimeout);
createEJBObjectStores(cacheSize, numberOfVictimsToSelect,
idleTimeout);
| EJBLocalObjectImpl | createEJBLocalObjectImpl()
throw new EJBException(
"INTERNAL ERROR: EntityContainer.createEJBLocalObjectImpl() called");
| EJBObjectImpl | createEJBObjectImpl()Implementation of BaseContainer method. This is never called.
throw new EJBException(
"INTERNAL ERROR: EntityContainer.createEJBObject() called");
| protected void | createEJBObjectStores(int cacheSize, int numberOfVictimsToSelect, long idleTimeout)
EJBObjectCache lru = null;
String ejbName = ejbDescriptor.getName();
idleTimeout = (idleTimeout <= 0) ? -1 : idleTimeout;
if (cacheSize <= 0 && idleTimeout <= 0) {
ejbObjectStore = new UnboundedEJBObjectCache(ejbName);
ejbObjectStore.init(DEFAULT_CACHE_SIZE, numberOfVictimsToSelect, 0L,
(float)1.0, null);
ejbLocalObjectStore = new UnboundedEJBObjectCache(ejbName);
ejbLocalObjectStore.init(DEFAULT_CACHE_SIZE,
numberOfVictimsToSelect, 0L, (float)1.0, null);
} else {
cacheSize = (cacheSize <= 0) ? DEFAULT_CACHE_SIZE : cacheSize;
ejbObjectStore = new FIFOEJBObjectCache(ejbName);
ejbObjectStore.init(cacheSize, numberOfVictimsToSelect, idleTimeout,
(float)1.0, null);
ejbObjectStore.setEJBObjectCacheListener(
new EJBObjectCacheVictimHandler());
ejbLocalObjectStore = new FIFOEJBObjectCache(ejbName);
ejbLocalObjectStore.init(cacheSize, numberOfVictimsToSelect,
idleTimeout, (float)1.0, null);
ejbLocalObjectStore.setEJBObjectCacheListener(
new LocalEJBObjectCacheVictimHandler());
}
if (idleTimeout > 0) {
idleEJBObjectPassivator = setupIdleBeansPassivator(ejbObjectStore);
idleLocalEJBObjectPassivator =
setupIdleBeansPassivator(ejbLocalObjectStore);
}
| protected EntityContextImpl | createEntityContextInstance(EntityBean ejb, com.sun.ejb.containers.EntityContainer entityContainer)
return new EntityContextImpl(ejb, entityContainer);
| protected void | createReadyStore(int cacheSize, int numberOfVictimsToSelect, float loadFactor, long idleTimeout)
idleTimeout = (idleTimeout <= 0) ? -1 : idleTimeout;
if (cacheSize <= 0 && idleTimeout <= 0) {
readyStore = new BaseCache();
cacheSize = DEFAULT_CACHE_SIZE;
readyStore.init(cacheSize, loadFactor, null);
} else {
cacheSize = (cacheSize <= 0) ? DEFAULT_CACHE_SIZE : cacheSize;
LruCache lru = new LruCache(DEFAULT_CACHE_SIZE);
if (numberOfVictimsToSelect >= 0) {
loadFactor = (float) (1.0 - (1.0 *
numberOfVictimsToSelect/cacheSize));
}
lru.init(cacheSize, idleTimeout, loadFactor, null);
readyStore = lru;
readyStore.addCacheListener(this);
}
if (idleTimeout > 0) {
idleBeansPassivator = setupIdleBeansPassivator(readyStore);
}
| protected void | destroyReadyStoreOnUndeploy()
if (readyStore == null) {
return;
}
// destroy all EJB instances in readyStore
synchronized ( readyStore ) {
Iterator beans = readyStore.values();
while ( beans.hasNext() ) {
EJBContextImpl ctx = (EJBContextImpl)beans.next();
transactionManager.ejbDestroyed(ctx);
}
}
readyStore.destroy();
readyStore = null;
| protected void | doFlush(Invocation inv)
if( !inv.invocationInfo.flushEnabled ||
inv.exception != null ) {
return;
}
if( !isContainerManagedPers ) {
//NEED TO INTERNATIONALIZE THIS WARNING MESSAGE
_logger.log(Level.WARNING,
"Cannot turn on flush-enabled-at-end-of-method for a bean with Bean Managed Persistence");
return;
}
InvocationInfo invInfo = inv.invocationInfo;
Throwable exception = inv.exception;
EntityContextImpl context = (EntityContextImpl)inv.context;
Transaction tx = context.getTransaction();
//Since postInvoke(Tx) has been called before the releaseContext, the transaction
//could be committed or rolledback. In that case there is no point to call flush
if( tx == null) {
return;
}
//return w/o doing anything if the transaction is marked for rollback
try {
if( context.getRollbackOnly() ) {
return;
}
} catch( Throwable ex ) {
_logger.log(Level.WARNING, "Exception when calling getRollbackOnly", ex);
return;
}
if ( invInfo.isBusinessMethod ) {
try {
//Store the state of all the beans that are part of this transaction
storeAllBeansInTx( tx );
} catch( Throwable ex ) {
inv.exception = ex;
return;
}
}
try {
BeanStateSynchronization pmcontract = (BeanStateSynchronization)inv.ejb;
pmcontract.ejb__flush();
} catch( Throwable ex ) {
//check the type of the method and create the corresponding exception
if( invInfo.startsWithCreate ) {
CreateException ejbEx = new CreateException();
ejbEx.initCause(ex);
inv.exception = ejbEx;
} else if( invInfo.startsWithRemove ) {
RemoveException ejbEx = new RemoveException();
ejbEx.initCause(ex);
inv.exception = ejbEx;
} else {
EJBException ejbEx = new EJBException();
ejbEx.initCause(ex);
inv.exception = ejbEx;
}
return;
}
| void | doTimerInvocationInit(Invocation inv, RuntimeTimerState timerState)
Object primaryKey = timerState.getTimedObjectPrimaryKey();
if( isRemote ) {
inv.ejbObject = internalGetEJBObjectImpl(primaryKey, null);
inv.isLocal = false;
} else {
inv.ejbObject = internalGetEJBLocalObjectImpl(primaryKey);
inv.isLocal = true;
}
if( inv.ejbObject == null ) {
throw new Exception("Timed object identity (" + primaryKey +
" ) no longer exists " );
}
| private void | enlistResourcesAndStore(EntityContextImpl context)
EntityBean e = (EntityBean)context.getEJB();
// NOTE : Use invocation instead of ComponentInvocation since
// the context is available. It is needed in case ejbStore/ejbLoad
// makes use of EJB timer service in order to perform operations allowed
// checks
Invocation inv = new Invocation(e, this);
inv.context = context;
invocationManager.preInvoke(inv);
try {
transactionManager.enlistComponentResources();
callEJBStore(e, context);
} catch ( NoSuchEntityException ex ) {
// Error during ejbStore, so discard bean: EJB2.0 18.3.3
forceDestroyBean(context);
throw new NoSuchObjectLocalException(
"NoSuchEntityException thrown by ejbStore, EJB instance discarded", ex);
} catch ( Exception ex ) {
// Error during ejbStore, so discard bean: EJB2.0 18.3.3
forceDestroyBean(context);
throw new EJBException(ex);
} finally {
invocationManager.postInvoke(inv);
}
| void | forceDestroyBean(EJBContextImpl ctx)Discard the bean instance. The bean's persistent state is not removed.
This is usually called when the bean instance throws a system exception,
from BaseContainer.postInvokeTx, getReadyEJB,
afterBegin, beforeCompletion, passivateEJB.
// Something bad happened (such as a RuntimeException),
// so kill the bean and let it be GC'ed
// Note: EJB2.0 section 18.3.1 says that discarding an EJB
// means that no methods other than finalize() should be invoked on it.
if ( ctx.getState() == DESTROYED ) {
entityCtxPool.destroyObject(null);
return;
}
EntityContextImpl context = (EntityContextImpl)ctx;
EntityBean ejb = (EntityBean)context.getEJB();
// Start of IAS 4661771
synchronized ( context ) {
try {
Object primaryKey = context.getPrimaryKey();
if ( primaryKey != null ) {
if ( context.getTransaction() != null ) {
Transaction txCurrent = context.getTransaction();
ActiveTxCache activeTxCache = (ActiveTxCache)
(((J2EETransaction) txCurrent).getActiveTxCache());
if (activeTxCache != null) {
// remove the context from the store
activeTxCache.remove(this, primaryKey);
}
}
// remove the context from readyStore as well
removeContextFromReadyStore(primaryKey, context);
if (context.getEJBObjectImpl() != null) {
removeEJBObjectFromStore(primaryKey);
}
if (context.getEJBLocalObjectImpl() != null) {
ejbLocalObjectStore.remove(primaryKey);
}
}
} catch ( Exception ex ) {
_logger.log(Level.FINE, "Exception in forceDestroyBean()", ex);
} finally {
try {
//Very importatnt to set the state as destroyed otherwise
// the pool.destroy might wrongly call unsetEntityContext
context.setState(DESTROYED);
entityCtxPool.destroyObject(context);
} catch (Exception ex) {
_logger.log(Level.FINE, "Exception in forceDestroyBean()",
ex);
}
}
}
// End of IAS 4661771
| public EJBLocalObject | getEJBLocalObjectForPrimaryKey(java.lang.Object pkey, EJBContext ctx)Called only from the Persistence Manager for EJB2.0 CMP EntityBeans.
Called only during cascade delete......
This is a private API between the PM and Container because there
is no standard API defined in EJB2.0 for the PM to get an EJBLocalObject
for a primary key (findByPrimaryKey cant be used because it may
not run in the same tx).
Example 1:
A cascadeDeletes B and B calls getA() (expected return value: null)
In the above case, getA() eventualy calls getEJBLocalObjectForPrimaryKey(PK_of_A, Ctx_of_B)
We first check if B is in the process of being cascade deleted by checking the
cascadeDeleteBeforeEJBRemove flag. If this flag is true, only then we bother to check if
the Context associated with the PK_of_A in this transaction is marked for cascade delete
which can be figured out by checking isCascadeDeleteAfterSuperEJBRemove() in A's context.
If A is marked for cascade delete then we return null else the EJBLocalObject associated
with A.
Example 2:
C cascadeDeletes B and B calls getA() (expected return value: EJBLocalObject for PK_of_A)
In the above case, getA() eventualy calls getEJBLocalObjectForPrimaryKey(PK_of_A, Ctx_of_B)
We first check if B is in the process of being cascade deleted by checking the
cascadeDeleteBeforeEJBRemove flag. This flag will be true, and hence we check if
the Context associated with the PK_of_A in this transaction is marked for cascade delete
which can be figured out by checking isCascadeDeleteAfterSuperEJBRemove() in A's context.
In this case this flag will be false and hcen we return the ejbLocalObject
Example 2:
B is *NOT* cascade deleted and B calls getA() (expected return value: EJBLocalObject for PK_of_A)
In the above case, getA() eventualy calls getEJBLocalObjectForPrimaryKey(PK_of_A, Ctx_of_B)
We first check if B is in the process of being cascade deleted by checking the
cascadeDeleteBeforeEJBRemove flag. This flag will be FALSE, and hence we do not make
any further check and return the EJBLocalObject associated with A
EntityContextImpl context = (EntityContextImpl) ctx;
EJBLocalObjectImpl ejbLocalObjectImpl =
internalGetEJBLocalObjectImpl(pkey);
if (context.isCascadeDeleteBeforeEJBRemove()) {
J2EETransaction current = null;
try {
current = (J2EETransaction) transactionManager.getTransaction();
} catch ( SystemException ex ) {
throw new EJBException(ex);
}
ActiveTxCache activeTxCache = (current == null) ? null :
(ActiveTxCache) (current.getActiveTxCache());
if (activeTxCache != null) {
EntityContextImpl ctx2 = (EntityContextImpl)
activeTxCache.get(this, pkey);
if ((ctx2 != null) &&
(ctx2.isCascadeDeleteAfterSuperEJBRemove())) {
return null;
}
}
return (EJBLocalObject) ejbLocalObjectImpl.getClientObject();
}
return (EJBLocalObject) ejbLocalObjectImpl.getClientObject();
| public EJBLocalObject | getEJBLocalObjectForPrimaryKey(java.lang.Object pkey)Called only from the Persistence Manager for EJB2.0 CMP EntityBeans.
This is a private API between the PM and Container because there
is no standard API defined in EJB2.0 for the PM to get an EJBLocalObject
for a primary key (findByPrimaryKey cant be used because it may
not run in the same tx).
EJBLocalObjectImpl localObjectImpl =
internalGetEJBLocalObjectImpl(pkey);
return (localObjectImpl != null) ?
(EJBLocalObject) localObjectImpl.getClientObject() : null;
| EJBLocalObjectImpl | getEJBLocalObjectImpl(java.lang.Object key)Called from EJBLocalObjectImpl.getLocalObject() while deserializing
a local object reference.
return internalGetEJBLocalObjectImpl(key);
| public EJBObject | getEJBObjectForPrimaryKey(java.lang.Object pkey)Called only from the Persistence Manager for EJB2.0 CMP EntityBeans.
This is a private API between the PM and Container because there
is no standard API defined in EJB2.0 for the PM to get an EJBObject
for a primary key (home.findByPrimaryKey cant be used because it may
not run in the same tx).
// create stub without creating EJBObject
return getEJBObjectStub(pkey, null);
| EJBObjectImpl | getEJBObjectImpl(byte[] streamKey)Called only from ContainerFactory when a remote invocation
arrives for an EJB.
// First get the primary key of the EJB
Object primaryKey;
try {
primaryKey = EJBUtils.deserializeObject(streamKey, loader, false);
} catch ( Exception ex ) {
throw new EJBException(ex);
}
return internalGetEJBObjectImpl(primaryKey, streamKey);
| EJBObject | getEJBObjectStub(java.lang.Object primaryKey, byte[] streamKey)
// primary key cant be null, streamkey may be null
// check if the EJBObject exists in the store.
try {
EJBObjectImpl ejbObjImpl =
(EJBObjectImpl) ejbObjectStore.get(primaryKey);
if ( (ejbObjImpl != null) && (ejbObjImpl.getStub() != null) ) {
return (EJBObject) ejbObjImpl.getStub();
}
// create a new stub without creating the EJBObject itself
if ( streamKey == null ) {
streamKey = EJBUtils.serializeObject(primaryKey, false);
}
EJBObject ejbStub = (EJBObject)
remoteHomeRefFactory.createRemoteReference(streamKey);
return ejbStub;
} catch ( Exception ex ) {
_logger.log(Level.FINE,"", ex);
throw new EJBException(ex);
}
| private EntityContextImpl | getEJBWithIncompleteTx(Invocation inv)Get an EJB instance for this EJBObject and current client Tx
Called only from getContext.
Return null if there no INCOMPLETE_TX bean for the pkey & tx.
// We need to make sure that two concurrent client
// invocations with same primary key and same client tx
// get the SAME EJB instance.
// So we need to maintain exactly one copy of an EJB's state
// per transaction.
J2EETransaction current = null;
try {
current = (J2EETransaction) transactionManager.getTransaction();
} catch ( SystemException ex ) {
throw new EJBException(ex);
}
EntityContextImpl ctx = null;
if (current != null) {
ActiveTxCache activeTxCache = (ActiveTxCache)
current.getActiveTxCache();
ctx = (activeTxCache == null)
? null : activeTxCache.get(this, inv.ejbObject.getKey());
inv.foundInTxCache = (ctx != null);
}
return ctx;
| private int | getEjbObjectStoreSize()/
//Methods of EntityBeanStatsProvider
public int getMaxCacheSize() {
int maxSize = 0;
if (readyStore != null) {
maxSize = (cacheProp.maxCacheSize <= 0)
? Integer.MAX_VALUE
: cacheProp.maxCacheSize;
}
return maxSize;
}
public int getSteadyPoolSize() {
return entityCtxPool.getSteadyPoolSize();
}
public int getMaxPoolSize() {
return entityCtxPool.getMaxPoolSize();
}
public long getPooledCount() {
return entityCtxPool.getSize();
}
public long getReadyCount() {
return (readyStore == null)
? 0
: readyStore.getEntryCount();
}
/
return ejbObjectStore.getEntryCount();
| public java.lang.String | getMonitorAttributeValues()
StringBuffer sbuf = new StringBuffer();
appendStats(sbuf);
return sbuf.toString();
| protected EntityContextImpl | getPooledEJB()
try {
return (EntityContextImpl) entityCtxPool.getObject(true, null);
} catch (com.sun.ejb.containers.util.pool.PoolException inEx) {
throw new EJBException(inEx);
}
| protected EntityContextImpl | getReadyEJB(Invocation inv)
Object primaryKey = inv.ejbObject.getKey();
EntityContextImpl context = null;
// Try and get an EJB instance for this primaryKey from the
// readyStore
context = (EntityContextImpl)readyStore.remove(primaryKey);
if (context == null || context.getState() != READY) {
context = activateEJBFromPool(primaryKey, inv);
}
return context;
| protected void | initializeHome()Called from the ContainerFactory during initialization.
ObjectFactory entityCtxFactory = new EntityContextFactory(this);
int steadyPoolSize = 0;
int resizeQuantity = 10;
int idleTimeoutInSeconds = Integer.MAX_VALUE-1;
poolProp = new PoolProperties();
super.initializeHome();
entityCtxPool = new NonBlockingPool(ejbDescriptor.getName(),
entityCtxFactory, poolProp.steadyPoolSize,
poolProp.poolResizeQuantity, poolProp.maxPoolSize,
poolProp.poolIdleTimeoutInSeconds, loader);
registerMonitorableComponents();
| protected EJBLocalObjectImpl | internalGetEJBLocalObjectImpl(java.lang.Object primaryKey)The following are private methods for implementing internal logic
for lifecyle and state management, in a reusable way.
return internalGetEJBLocalObjectImpl(primaryKey, false,
defaultCacheEJBO);
| protected EJBLocalObjectImpl | internalGetEJBLocalObjectImpl(java.lang.Object primaryKey, boolean incrementRefCount)
return internalGetEJBLocalObjectImpl(primaryKey, incrementRefCount,
defaultCacheEJBO);
| protected EJBLocalObjectImpl | internalGetEJBLocalObjectImpl(java.lang.Object primaryKey, boolean incrementRefCount, boolean cacheEJBO)
// check if the EJBLocalObject exists in the store.
try {
EJBLocalObjectImpl localObjImpl = (EJBLocalObjectImpl)
ejbLocalObjectStore.get(primaryKey, incrementRefCount);
if ( localObjImpl == null ) {
localObjImpl = instantiateEJBLocalObjectImpl();
// associate the EJBLocalObjectImpl with the primary key
localObjImpl.setKey(primaryKey);
// add the EJBLocalObjectImpl to ejbLocalObjectStore
if (incrementRefCount || cacheEJBO) {
ejbLocalObjectStore.put(primaryKey, localObjImpl,
incrementRefCount);
}
}
return localObjImpl;
} catch ( Exception ex ) {
_logger.log(Level.SEVERE,"ejb.get_ejb_local_object_exception",
logParams);
_logger.log(Level.SEVERE,"",ex);
throw new EJBException(ex);
}
| protected EJBObjectImpl | internalGetEJBObjectImpl(java.lang.Object primaryKey, byte[] streamKey)
return internalGetEJBObjectImpl(primaryKey, streamKey, false,
defaultCacheEJBO);
| protected EJBObjectImpl | internalGetEJBObjectImpl(java.lang.Object primaryKey, byte[] streamKey, boolean incrementRefCount)
return internalGetEJBObjectImpl
(primaryKey, streamKey, incrementRefCount, defaultCacheEJBO);
| protected EJBObjectImpl | internalGetEJBObjectImpl(java.lang.Object primaryKey, byte[] streamKey, boolean incrementRefCount, boolean cacheEJBO)
// primary key cant be null, streamkey may be null
// check if the EJBContext/EJBObject exists in the store.
try {
EJBObjectImpl ejbObjImpl = (EJBObjectImpl)
ejbObjectStore.get(primaryKey, incrementRefCount);
if ( (ejbObjImpl != null) && (ejbObjImpl.getStub() != null) ) {
return ejbObjImpl;
}
// check if the EJBContext/EJBObject exists in threadlocal
// This happens if ejbo is in the process of being created.
// This is necessary to prevent infinite recursion
// because PRO.narrow calls is_a which calls the
// ProtocolMgr which calls getEJBObject.
ejbObjImpl = (EJBObjectImpl) ejbServant.get();
if ( ejbObjImpl != null ) {
return ejbObjImpl;
}
// create the EJBObject.
ejbObjImpl = instantiateEJBObjectImpl();
// associate the EJBObject with the primary key
ejbObjImpl.setKey(primaryKey);
// set ejbo in thread local to help recursive calls find the ejbo
ejbServant.set(ejbObjImpl);
// "Connect" the EJBObject to the Protocol Manager
if ( streamKey == null ) {
streamKey = EJBUtils.serializeObject(primaryKey, false);
}
EJBObject ejbStub = (EJBObject)
remoteHomeRefFactory.createRemoteReference(streamKey);
ejbObjImpl.setStub(ejbStub);
ejbServant.set(null);
if ((incrementRefCount || cacheEJBO)) {
EJBObjectImpl ejbo1 =
(EJBObjectImpl) ejbObjectStore.put(primaryKey, ejbObjImpl,
incrementRefCount);
if ((ejbo1 != null) && (ejbo1 != ejbObjImpl)) {
remoteHomeRefFactory.destroyReference(ejbObjImpl.getStub(),
ejbObjImpl);
ejbObjImpl = ejbo1;
}
}
return ejbObjImpl;
}
catch ( Exception ex ) {
_logger.log(Level.FINE, "ejb.get_ejb_context_exception", logParams);
_logger.log(Level.FINE,"",ex);
throw new EJBException(ex);
}
| private void | internalRemoveBeanUnchecked(EJBLocalRemoteObject localRemoteObj, boolean local)Remove a bean. Used by the PersistenceManager.
This is needed because the PM's remove must bypass tx/security checks.
Invocation inv = new Invocation();
inv.ejbObject = localRemoteObj;
inv.isLocal = local;
Method method=null;
try {
method = EJBLocalObject.class.getMethod("remove", NO_PARAMS);
} catch ( NoSuchMethodException e ) {
_logger.log(Level.FINE,
"Exception in internalRemoveBeanUnchecked()", e);
}
inv.method = method;
inv.invocationInfo = (InvocationInfo) invocationInfoMap.get(method);
try {
// First get a bean instance on which ejbRemove can be invoked.
// This code must be in sync with getContext().
// Can't call getContext() directly because it does stuff
// based on remove's txAttr.
// Assume there is a tx on the current thread.
EntityContextImpl context = getEJBWithIncompleteTx(inv);
if ( context == null ) {
context = getReadyEJB(inv);
}
synchronized ( context ) {
if ( context.getState() == INVOKING && !isReentrant ) {
throw new EJBException(
"EJB is already executing another request");
}
if (context.getState() == POOLED ||
context.getState() == DESTROYED) {
// somehow a concurrent thread must have changed state.
// this is an internal error.
throw new EJBException("Internal error: unknown EJB state");
}
context.setState(INVOKING);
}
inv.context = context;
context.setLastTransactionStatus(-1);
context.incrementCalls();
inv.instance = inv.ejb = context.getEJB();
inv.container = this;
invocationManager.preInvoke(inv);
// call ejbLoad if necessary
useClientTx(context.getTransaction(), inv);
try {
context.setCascadeDeleteBeforeEJBRemove(true);
removeBean(inv);
} catch ( Exception ex ) {
_logger.log(Level.FINE,
"Exception in internalRemoveBeanUnchecked()", ex);
// if system exception mark the tx for rollback
inv.exception = checkExceptionClientTx(context, ex);
}
if ( inv.exception != null ) {
throw inv.exception;
}
}
catch ( RuntimeException ex ) {
throw ex;
}
catch ( Exception ex ) {
throw new EJBException(ex);
}
catch ( Throwable ex ) {
EJBException ejbEx = new EJBException();
ejbEx.initCause(ex);
throw ejbEx;
}
finally {
invocationManager.postInvoke(inv);
releaseContext(inv);
}
| protected java.lang.Object | invokeFindByPrimaryKey(java.lang.reflect.Method method, Invocation inv, java.lang.Object[] args)
Object pKeys = super.invokeTargetBeanMethod(method,
inv, inv.ejb, args, null);
return postFind(inv, pKeys, null);
| boolean | isIdentical(EJBObjectImpl ejbObjImpl, EJBObject other)
if ( other == ejbObjImpl.getStub() ) {
return true;
} else {
try {
// EJBObject may be a remote object.
// Compare homes. See EJB2.0 spec section 9.8.
if ( !protocolMgr.isIdentical(ejbHomeStub,
other.getEJBHome()))
return false;
// Compare primary keys.
if (!ejbObjImpl.getPrimaryKey().equals(other.getPrimaryKey())) {
return false;
}
return true;
} catch ( Exception ex ) {
_logger.log(Level.INFO, "ejb.ejb_comparison_exception",
logParams);
_logger.log(Level.INFO, "", ex);
throw new RemoteException("Exception in isIdentical()", ex);
}
}
| public void | onReady()
| protected void | passivateAndPoolEJB(EntityContextImpl context)
if ( context.getState() == DESTROYED || context.getState() == POOLED )
return;
// if ( context.isPooled() ) {
// context.isPooled(false);
// return;
// }
EntityBean ejb = (EntityBean) context.getEJB();
synchronized ( context ) {
Invocation inv = new Invocation(ejb, this, context);
inv.method = ejbPassivateMethod;
invocationManager.preInvoke(inv);
try {
ejb.ejbPassivate();
} catch ( Exception ex ) {
_logger.log(Level.FINE,"Exception in passivateAndPoolEJB()",ex);
forceDestroyBean(context);
return;
} finally {
invocationManager.postInvoke(inv);
}
// remove EJB(Local)Object from ejb(Local)ObjectStore
Object primaryKey = context.getPrimaryKey();
if ( isRemote ) {
removeEJBObjectFromStore(primaryKey);
}
if ( isLocal ) {
ejbLocalObjectStore.remove(primaryKey);
}
addPooledEJB(context);
}
| boolean | passivateEJB(ComponentContext ctx)
if (containerState != CONTAINER_STARTED) {
return false;
}
EntityContextImpl context = (EntityContextImpl)ctx;
if (context.getState() != READY) {
return false;
}
if(_logger.isLoggable(Level.FINEST)) {
_logger.log(Level.FINEST,"EntityContainer.passivateEJB(): context = (" +
ctx + ")");
}
EntityBean ejb = (EntityBean)context.getEJB();
Invocation inv = new Invocation(ejb, this, context);
inv.method = ejbPassivateMethod;
Object pkey = context.getPrimaryKey();
boolean wasPassivated = false;
// check state after locking ctx
if ( context.getState() != READY )
return false;
try {
invocationManager.preInvoke(inv);
// remove EJB from readyStore
removeContextFromReadyStore(pkey, context);
// no Tx needed for ejbPassivate
ejb.ejbPassivate();
wasPassivated = true;
} catch ( Exception ex ) {
_logger.log(Level.FINE, "Exception in passivateEJB()", ex);
// Error during ejbStore/Passivate, discard bean: EJB2.0 18.3.3
forceDestroyBean(context);
return false;
} finally {
invocationManager.postInvoke(inv);
}
// Remove the ejbObject/LocalObject from ejbObject/LocalObjectStore
// If a future invocation arrives for them, they'll get recreated.
if ( isRemote ) {
removeEJBObjectFromStore(pkey);
}
if ( isLocal ) {
ejbLocalObjectStore.remove(pkey);
}
// Note: ejbStore and ejbPassivate need the primarykey
// so we should dissociate the context from EJBObject only
// after calling ejbStore and ejbPassivate.
synchronized (context) {
addPooledEJB(context);
}
return wasPassivated;
| public void | postCreate(Invocation inv, java.lang.Object primaryKey)This is called from the generated "HelloEJBHomeImpl" create* method,
after ejb.ejbCreate() has been called and before ejb.ejbPostCreate()
is called.
Note: postCreate will not be called if ejbCreate throws an exception
if ( primaryKey == null )
throw new EJBException(
"Null primary key returned by ejbCreate method");
EntityContextImpl context = (EntityContextImpl)inv.context;
EJBObjectImpl ejbObjImpl = null;
EJBLocalObjectImpl localObjImpl = null;
if ( (isRemote) && (!inv.isLocal) ) {
// remote invocation: create EJBObject
ejbObjImpl = internalGetEJBObjectImpl(primaryKey, null, true);
// associate the context with the ejbObject
context.setEJBObjectImpl(ejbObjImpl);
context.setEJBStub((EJBObject)ejbObjImpl.getStub());
}
if ( isLocal ) {
// create EJBLocalObject irrespective of local/remote invocation
// this is necessary to make EntityContext.getPrimaryKey and
// EntityContext.getEJBObject work.
localObjImpl = internalGetEJBLocalObjectImpl(primaryKey, true);
// associate the context with the ejbLocalObject
context.setEJBLocalObjectImpl(localObjImpl);
}
if ( inv.isLocal )
inv.ejbObject = localObjImpl;
else
inv.ejbObject = ejbObjImpl;
if ( context.getTransaction() != null ) {
// Add EJB to INCOMPLETE_TX table so that concurrent/loopback
// invocations will be correctly handled
addIncompleteTxEJB(context);
}
context.setDirty(true); // ejbPostCreate could modify state
| public java.lang.Object | postFind(Invocation inv, java.lang.Object primaryKeys, java.lang.Object[] findParams)Convert a collection of primary keys to a collection of EJBObjects.
(special case: single primary key).
Note: the order of input & output collections must be maintained.
Null values are preserved in both the single primary key return
and collection-valued return cases.
This is called from the generated "HelloEJBHomeImpl" find* method,
after ejb.ejbFind**() has been called.
Note: postFind will not be called if ejbFindXXX throws an exception
if ( primaryKeys instanceof Enumeration ) {
// create Enumeration of objrefs from Enumeration of primaryKeys
Enumeration e = (Enumeration)primaryKeys;
// this is a portable Serializable Enumeration
ObjrefEnumeration objrefs = new ObjrefEnumeration();
while ( e.hasMoreElements() ) {
Object primaryKey = e.nextElement();
Object ref;
if( primaryKey != null ) {
if ( inv.isLocal )
ref = getEJBLocalObjectForPrimaryKey(primaryKey);
else
ref = getEJBObjectStub(primaryKey, null);
objrefs.add(ref);
} else {
objrefs.add(null);
}
}
return objrefs;
} else if ( primaryKeys instanceof Collection ) {
// create Collection of objrefs from Collection of primaryKeys
Collection c = (Collection)primaryKeys;
Iterator it = c.iterator();
ArrayList objrefs = new ArrayList(); // a Serializable Collection
while ( it.hasNext() ) {
Object primaryKey = it.next();
Object ref;
if( primaryKey != null ) {
if ( inv.isLocal )
ref = getEJBLocalObjectForPrimaryKey(primaryKey);
else
ref = getEJBObjectStub(primaryKey, null);
objrefs.add(ref);
} else {
objrefs.add(null);
}
}
return objrefs;
} else {
if( primaryKeys != null ) {
if ( inv.isLocal )
return getEJBLocalObjectForPrimaryKey(primaryKeys);
else
return getEJBObjectStub(primaryKeys, null);
} else {
return null;
}
}
| void | postInvokeNoTx(Invocation inv)
// This calls ejbStore to allow bean to flush any state to database.
// This is also sufficient for compliance with EJB2.0 section 12.1.6.1
// (ejbStore must be called between biz method and ejbPassivate).
beforeCompletion((EJBContextImpl)inv.context);
| protected InvocationInfo | postProcessInvocationInfo(InvocationInfo invInfo)
Method method = invInfo.method;
boolean isCMPField = isContainerManagedPers && invInfo.isBusinessMethod
&& invInfo.methodIntf.equals(MethodDescriptor.EJB_LOCAL);
if (isCMPField) {
String methodName = method.getName();
isCMPField = methodName.startsWith("get")
|| methodName.startsWith("set");
if (isCMPField) {
try {
//ejbClass is the container-generated implementation class.
//Need to get its superclass, which is provided by the bean provider.
Method methodInBeanClass = ejbClass.getSuperclass().getMethod(
methodName, method.getParameterTypes());
isCMPField = Modifier.isAbstract(methodInBeanClass.getModifiers());
} catch (NoSuchMethodException ignore) {
isCMPField = false;
}
}
}
invInfo.isTxRequiredLocalCMPField = isCMPField
&& (invInfo.txAttr == TX_REQUIRED);
return invInfo;
| protected void | preCreate(Invocation inv, EntityContextImpl context)Called from getContext before the ejb.ejbCreate is called
statCreateCount++;
| protected void | preFind(Invocation inv, EntityContextImpl context)Called from getContext before the ejb.ejbFind* is called
// if the finder is being invoked with the client's transaction,
// call ejbStore on all dirty bean instances associated with that
// transaction. This ensures that the finder results will include
// all updates done previously in the client's tx.
if ( willInvokeWithClientTx(inv) &&
!inv.method.getName().equals("findByPrimaryKey") ) {
Transaction tx = null;
try {
tx = transactionManager.getTransaction();
} catch ( SystemException ex ) {
throw new EJBException(ex);
}
storeAllBeansInTx( tx );
}
| protected void | preInitialize(EjbDescriptor desc, java.lang.ClassLoader loader)
EjbEntityDescriptor ed = (EjbEntityDescriptor)desc;
isReentrant = ed.isReentrant();
if ( ed.getPersistenceType().equals(
EjbEntityDescriptor.BEAN_PERSISTENCE) ) {
isContainerManagedPers = false;
} else {
isContainerManagedPers = true;
}
_logger.log(Level.FINE,"[EntityContainer] preInitialize==>isContainerManagedPers: "
+ isContainerManagedPers);
| void | preInvokeNoTx(Invocation inv)
EntityContextImpl context = (EntityContextImpl)inv.context;
if ( context.getState() == DESTROYED ) {
return;
}
if ( context.isNewlyActivated() &&
!inv.invocationInfo.isCreateHomeFinder ) {
// follow EJB2.0 section 12.1.6.1
EntityBean e = (EntityBean)context.getEJB();
try {
callEJBLoad(e, context, false);
} catch ( NoSuchEntityException ex ) {
// Error during ejbLoad, so discard bean: EJB2.0 18.3.3
forceDestroyBean(context);
throw new NoSuchObjectLocalException(
"NoSuchEntityException thrown by ejbLoad, EJB instance discarded", ex);
} catch ( Exception ex ) {
// Error during ejbLoad, so discard bean: EJB2.0 18.3.3
forceDestroyBean(context);
throw new EJBException(ex);
}
context.setNewlyActivated(false);
}
| public void | preSelect()Called from CMP PersistentManager
// if the ejbSelect is being invoked with the client's transaction,
// call ejbStore on all dirty bean instances associated with that
// transaction. This ensures that the select results will include
// all updates done previously in the client's tx.
_logger.fine(" inside preSelect...");
Transaction tx = null;
try {
_logger.fine("PRESELECT : getting transaction...");
tx = transactionManager.getTransaction();
} catch ( SystemException ex ) {
throw new EJBException(ex);
}
_logger.fine("PRESELECT : calling storeAllBeansInTx()...");
storeAllBeansInTx( tx );
| protected void | registerMonitorableComponents()
registryMediator.registerProvider(this);
registryMediator.registerProvider(entityCtxPool);
if (readyStore != null) {
int confMaxCacheSize = cacheProp.maxCacheSize;
if (confMaxCacheSize <= 0) {
confMaxCacheSize = Integer.MAX_VALUE;
}
this.cacheStatsProvider = new EntityCacheStatsProvider(
(BaseCache) readyStore, confMaxCacheSize);
registryMediator.registerProvider(cacheStatsProvider);
}
super.registerMonitorableComponents();
super.populateMethodMonitorMap();
_logger.log(Level.FINE, "[Entity Container] registered monitorable");
| public void | releaseContext(Invocation inv)This is called from BaseContainer.postInvoke after
EntityContainer.preInvokeTx has been called.
EntityContextImpl context = (EntityContextImpl)inv.context;
boolean decrementedCalls = false; // End of IAS 4661771
if ( context.getState()==DESTROYED )
return;
try {
if ( context.hasReentrantCall() ) {
// For biz->biz or postCreate->biz, the bean instance will
// remain in the incomplete-tx table.
if ( inv.ejbObject.isRemoved() ) {
// biz -> remove case (biz method invoked reentrant remove)
// Remove from IncompleteTx table, to prevent further
// reentrant calls.
removeIncompleteTxEJB(context, true);
// disconnect context from EJB(Local)Object so that
// context.getEJBObject() will throw exception.
if ( context.getEJBObjectImpl() != null ) {
// reset flag in case EJBObject is used again
context.getEJBObjectImpl().setRemoved(false);
context.setEJBObjectImpl(null);
context.setEJBStub(null);
}
if ( context.getEJBLocalObjectImpl() != null ) {
// reset flag in case EJBLocalObject is used again
context.getEJBLocalObjectImpl().setRemoved(false);
context.setEJBLocalObjectImpl(null);
}
} else {
if ( context.getState() == INVOKING ) {
doFlush( inv );
}
}
// Note: at this point context.getState() is INVOKING.
} else if ( context.getEJBObjectImpl()==null
&& context.getEJBLocalObjectImpl()==null ) {
// This can only happen if the method was ejbFind
// OR if the method was ejbCreate which threw an application
// exception (so postCreate was not called)
// OR after a biz method which called a reentrant remove.
// So bean instance goes back into pool.
// We dont care if any Tx has completed or not.
//context.setTransaction(null);
decrementedCalls = true;
context.decrementCalls();
if (!(inv.invocationInfo.startsWithCreate)) {
context.setTransaction(null);
addPooledEJB(context);
}else if(context.getTransaction() == null) {
addPooledEJB(context);
} else {
// Set the state to incomplete as the transaction
// is not done still and afterCompletion will
// handle stuff
context.setState(INCOMPLETE_TX);
}
} else if ( inv.ejbObject.isRemoved() ) {
// EJBObject/LocalObject was removed, so bean instance
// goes back into pool.
// We dont care if any Tx has completed or not.
removeIncompleteTxEJB(context, true);
// unset the removed flag, in case the EJB(Local)Object
// ref is held by the client and is used again
if ( context.getEJBObjectImpl() != null )
context.getEJBObjectImpl().setRemoved(false);
if ( context.getEJBLocalObjectImpl() != null )
context.getEJBLocalObjectImpl().setRemoved(false);
decrementedCalls = true;
context.decrementCalls();
if(context.getTransaction() == null) {
addPooledEJB(context);
} else {
// Set the state to incomplete as the transaction
// is not done still and afterCompletion will
// handle stuff
context.setState(INCOMPLETE_TX);
}
} else if ( context.getTransaction() == null ) {
// biz methods and ejbCreate
// Either the EJB was called with no tx,
// or it was called with a tx which finished,
// so afterCompletion was already called.
// If no tx or tx committed, then move the EJB to READY state
// else pool the bean
int status = context.getLastTransactionStatus();
decrementedCalls = true;
context.decrementCalls();
context.setLastTransactionStatus(-1);
if ( status == -1 || status == Status.STATUS_COMMITTED
|| status == Status.STATUS_NO_TRANSACTION )
addReadyEJB(context);
else
passivateAndPoolEJB(context);
} else {
// biz methods and ejbCreate
// The EJB is still associated with a Tx.
// It will already be in the INCOMPLETE_TX table.
context.setState(INCOMPLETE_TX);
doFlush( inv );
}
} catch ( Exception ex ) {
_logger.log(Level.FINE, "ejb.release_context_exception",
logParams);
_logger.log(Level.FINE, "",ex);
throw new EJBException(ex);
} finally {
if (decrementedCalls == false) {
context.decrementCalls();
}
context.touch();
}
| protected void | removeBean(java.lang.Object primaryKey, java.lang.reflect.Method removeMethod, boolean local)
EJBLocalRemoteObject ejbo;
if ( local ) {
ejbo = internalGetEJBLocalObjectImpl(primaryKey, false, true);
}
else { // may be remote-only bean
ejbo = internalGetEJBObjectImpl(primaryKey, null, false, true);
}
removeBean(ejbo, removeMethod, local);
| protected void | removeBean(EJBLocalRemoteObject ejbo, java.lang.reflect.Method removeMethod, boolean local)
Invocation i = new Invocation();
i.ejbObject = ejbo;
i.isLocal = local;
i.method = removeMethod;
// Method must be a remove method defined on one of :
// javax.ejb.EJBHome, javax.ejb.EJBObject, javax.ejb.EJBLocalHome,
// javax.ejb.EJBLocalObject
Class declaringClass = removeMethod.getDeclaringClass();
i.isHome = ( (declaringClass == javax.ejb.EJBHome.class) ||
(declaringClass == javax.ejb.EJBLocalHome.class) );
try {
preInvoke(i);
removeBean(i);
} catch(Exception e) {
_logger.log(Level.SEVERE,"ejb.preinvoke_exception",logParams);
_logger.log(Level.SEVERE,"",e);
i.exception = e;
} finally {
postInvoke(i);
}
if(i.exception != null) {
if(i.exception instanceof RemoveException) {
throw (RemoveException)i.exception;
}
else if(i.exception instanceof RuntimeException) {
throw (RuntimeException)i.exception;
}
else if(i.exception instanceof Exception) {
throw new EJBException((Exception)i.exception);
}
else {
EJBException ejbEx = new EJBException();
ejbEx.initCause(i.exception);
throw ejbEx;
}
}
| protected void | removeBean(Invocation inv)container.preInvoke() must already be done.
So this will be called with the proper Tx context.
try {
statRemoveCount++;
// Note: if there are concurrent invocations/transactions in
// progress for this ejbObject, they will be serialized along with
// this remove by the database. So we optimistically do ejbRemove.
// call ejbRemove on the EJB
// the EJB is allowed to veto the remove by throwing RemoveException
EntityBean ejb = (EntityBean)inv.ejb;
EntityContextImpl context = (EntityContextImpl)inv.context;
callEJBRemove(ejb, context);
// inv.ejbObject could be a EJBObject or a EJBLocalObject
Object primaryKey = inv.ejbObject.getKey();
if ( isRemote ) {
removeEJBObjectFromStore(primaryKey);
// Mark EJB as removed. Now releaseContext will add bean to pool
if ( context.getEJBObjectImpl() != null ) {
context.getEJBObjectImpl().setRemoved(true);
}
}
if ( isLocal ) {
// Remove the EJBLocalObject from ejbLocalObjectStore
ejbLocalObjectStore.remove(primaryKey);
// Mark EJB as removed. Now releaseContext will add bean to pool
if ( context.getEJBLocalObjectImpl() != null ) {
context.getEJBLocalObjectImpl().setRemoved(true);
}
}
// Remove any timers for this entity bean identity.
EJBTimerService ejbTimerService =
containerFactory.getEJBTimerService();
if( (ejbTimerService != null) && isTimedObject() ) {
ejbTimerService.cancelEntityBeanTimers(getContainerId(),
primaryKey);
}
} catch ( RemoveException ex ) {
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,"ejb.local_remove_exception",logParams);
_logger.log(Level.FINE,"",ex);
}
throw ex;
}
catch ( Exception ex ) {
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,"ejb.remove_bean_exception",logParams);
_logger.log(Level.FINE,"",ex);
}
throw new EJBException(ex);
}
| public void | removeBeanUnchecked(EJBLocalObject localObj)Remove a bean. Used by the PersistenceManager.
This is needed because the PM's remove must bypass tx/security checks.
// First convert client EJBLocalObject to EJBLocalObjectImpl
EJBLocalObjectImpl localObjectImpl =
EJBLocalObjectImpl.toEJBLocalObjectImpl(localObj);
internalRemoveBeanUnchecked(localObjectImpl, true);
| public void | removeBeanUnchecked(java.lang.Object primaryKey)Remove a bean. Used by the PersistenceManager.
This is needed because the PM's remove must bypass tx/security checks.
EJBLocalRemoteObject ejbo;
if ( isLocal ) {
ejbo = internalGetEJBLocalObjectImpl(primaryKey);
internalRemoveBeanUnchecked(ejbo, true);
}
else { // remote-only bean
ejbo = internalGetEJBObjectImpl(primaryKey, null);
internalRemoveBeanUnchecked(ejbo, false);
}
| protected void | removeContextFromReadyStore(java.lang.Object primaryKey, EntityContextImpl context)
readyStore.remove(primaryKey, context);
| private void | removeEJBObjectFromStore(java.lang.Object primaryKey)
removeEJBObjectFromStore(primaryKey, true);
| private void | removeEJBObjectFromStore(java.lang.Object primaryKey, boolean decrementRefCount)
// Remove the EJBObject from ejbObjectStore so future lookups
// in internalGetEJBObject will not get it.
EJBObjectImpl ejbObjImpl =
(EJBObjectImpl)ejbObjectStore.remove(primaryKey, decrementRefCount);
if ( ejbObjImpl != null ) {
synchronized ( ejbObjImpl ) {
// disconnect the EJBObject from the ProtocolManager
// so that no remote invocations can reach the EJBObject
remoteHomeRefFactory.destroyReference(ejbObjImpl.getStub(),
ejbObjImpl.getEJBObject());
}
}
| protected void | removeIncompleteTxEJB(EntityContextImpl context, boolean updateTxBeanTable)Called from releaseContext if ejb is removed, from afterCompletion,
and from passivateEJB.
J2EETransaction current = (J2EETransaction) context.getTransaction();
if (current == null) {
return;
}
if ( (context.getEJBObjectImpl() == null) &&
(context.getEJBLocalObjectImpl() == null) ) {
return;
}
ActiveTxCache activeTxCache = (ActiveTxCache)
(((J2EETransaction) current).getActiveTxCache());
if (activeTxCache != null) {
activeTxCache.remove(this, context.getPrimaryKey());
}
if ( updateTxBeanTable ) {
Vector beans = containerFactory.getBeans(current);
beans.remove(context); // this is a little expensive...
}
| public com.sun.ejb.containers.EntityContainer$IdleBeansPassivator | setupIdleBeansPassivator(com.sun.appserv.util.cache.Cache cache)setup a timer task to trim timed out entries in the cache.
IdleBeansPassivator idleBeansPassivator =
new IdleBeansPassivator(cache);
ContainerFactoryImpl.getTimer().
scheduleAtFixedRate(idleBeansPassivator, idleTimeout, idleTimeout);
return idleBeansPassivator;
| private void | storeAllBeansInTx(javax.transaction.Transaction tx)
// Call ejbStore on all entitybeans in tx for all EntityContainers
Vector beans = containerFactory.getBeans(tx);
if ( beans.isEmpty() ) {
// No beans associated with the current transaction
return;
}
Iterator itr = beans.iterator();
while ( itr.hasNext() ) {
EntityContextImpl ctx = (EntityContextImpl)itr.next();
if ( ctx.getState() == INCOMPLETE_TX && ctx.isDirty() ) {
// Call ejbStore on the bean
// Note: the bean may be in a different container instance
EntityContainer cont = (EntityContainer)ctx.getContainer();
cont.enlistResourcesAndStore(ctx);
}
}
| public void | trimEvent(java.lang.Object primaryKey, java.lang.Object context)
boolean addTask = false;
synchronized (asyncTaskSemaphore) {
passivationCandidates.add(context);
if (addedASyncTask == true) {
return;
}
addTask = addedASyncTask = true;
}
try {
ASyncPassivator work = new ASyncPassivator();
ContainerWorkPool.addLast(work);
} catch (Exception ex) {
addedASyncTask = false;
_logger.log(Level.WARNING, "ejb.add_cleanup_task_error",ex);
}
| public void | undeploy()
//Change the container state to ensure that all new invocations will be rejected
super.setUndeployedState();
String ejbName = ejbDescriptor.getName();
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,"[EntityContainer]: Undeploying " + ejbName +
" ...");
}
// destroy all EJBObject refs
try {
Iterator elements = ejbObjectStore.values();
while ( elements.hasNext() ) {
EJBObjectImpl ejbObjImpl = (EJBObjectImpl) elements.next();
try {
if ( isRemote ) {
remoteHomeRefFactory.destroyReference
(ejbObjImpl.getStub(), ejbObjImpl.getEJBObject());
}
} catch ( Exception ex ) {
_logger.log(Level.FINE, "Exception in undeploy()", ex);
}
}
ejbObjectStore.destroy(); //store must set the listern to null
ejbObjectStore = null;
ejbLocalObjectStore.destroy(); //store must set the listern to null
ejbLocalObjectStore = null;
// destroy all EJB instances in readyStore
destroyReadyStoreOnUndeploy(); //cache must set the listern to null
// destroy all EJB instances in ActiveTxCache
/*
synchronized ( incompleteTxStore ) {
Iterator beans = incompleteTxStore.values();
while ( beans.hasNext() ) {
EJBContextImpl ctx = (EJBContextImpl)beans.next();
transactionManager.ejbDestroyed(ctx);
}
}
*/
entityCtxPool.close();
// stops the idle bean passivator and also removes the link
// to the cache; note that cancel() method of timertask
// does not remove the task from the timer's queue
if (idleBeansPassivator != null) {
try {
idleBeansPassivator.cancel();
} catch (Exception e) {
_logger.log(Level.FINE,
"[EntityContainer] cancelTimerTask: ", e);
}
this.idleBeansPassivator.cache = null;
}
cancelTimerTasks();
}
finally {
super.undeploy();
// helps garbage collection
this.ejbObjectStore = null;
this.ejbLocalObjectStore = null;
this.passivationCandidates = null;
this.readyStore = null;
this.entityCtxPool = null;
this.iased = null;
this.beanCacheDes = null;
this.beanPoolDes = null;
this.svr = null;
this.cfg = null;
this.ejbContainer = null;
this.cacheProp = null;
this.poolProp = null;
this.asyncTaskSemaphore = null;
this.idleBeansPassivator = null;
}
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE," [EntityContainer]: Successfully Undeployed " +
ejbName);
}
| protected boolean | willInvokeWithClientTx(Invocation inv)
int status = Status.STATUS_UNKNOWN;
try {
Integer preInvokeTxStatus = inv.getPreInvokeTxStatus();
status = (preInvokeTxStatus != null) ?
preInvokeTxStatus.intValue() : transactionManager.getStatus();
} catch ( SystemException ex ) {
throw new EJBException(ex);
}
if ( status != Status.STATUS_NO_TRANSACTION ) {
int txAttr = inv.invocationInfo.txAttr;
switch (txAttr) {
case TX_SUPPORTS:
case TX_REQUIRED:
case TX_MANDATORY:
return true;
}
}
return false;
|
|