MessageBeanContainerpublic final class MessageBeanContainer extends BaseContainer implements MessageBeanProtocolManager, com.sun.ejb.spi.stats.MessageDrivenBeanStatsProviderThis class provides container functionality specific to message-driven
EJBs.
At deployment time, one instance of the MessageDrivenBeanContainer is
created for each message-driven bean in an application.
The 3 states of a Message-driven EJB (an EJB can be in only 1 state
at a time):
1. POOLED : ready for invocations, no transaction in progress
2. INVOKING : processing an invocation
3. DESTROYED : does not exist
A Message-driven Bean can hold open DB connections across invocations.
It's assumed that the Resource Manager can handle
multiple incomplete transactions on the same
connection. |
Fields Summary |
---|
private static final Logger | _logger | private String | appEJBName_ | private static com.sun.enterprise.util.LocalStringManagerImpl | localStrings | private static final int | POOLED | private static final int | INVOKING | private static final int | DESTROYED | private MessageBeanClient | messageBeanClient_ | private com.sun.ejb.containers.util.pool.AbstractPool | messageBeanPool_ | private com.sun.enterprise.deployment.runtime.BeanPoolDescriptor | beanPoolDesc_ | private int | maxMessageBeanListeners_ | private int | numMessageBeanListeners_ | private static final String | MESSAGE_BEAN_CLIENT_FACTORY_PROP | private static final String | DEFAULT_MESSAGE_BEAN_CLIENT_FACTORY | private static final int | DEFAULT_RESIZE_QUANTITY | private static final int | DEFAULT_STEADY_SIZE | private static final int | DEFAULT_MAX_POOL_SIZE | private static final int | DEFAULT_IDLE_TIMEOUT | private static final int | MIN_IDLE_TIMEOUT | private int | statMessageCount |
Constructors Summary |
---|
MessageBeanContainer(com.sun.enterprise.deployment.EjbDescriptor desc, ClassLoader loader)
super(desc, loader);
appEJBName_ =
desc.getApplication().getRegistrationName() + ":" +desc.getName();
EjbMessageBeanDescriptor msgBeanDesc =
(EjbMessageBeanDescriptor) desc;
try {
// Register the tx attribute for each method on MessageListener
// interface. NOTE : These method objects MUST come from the
// MessageListener interface, NOT the bean class itself. This
// is because the message bean container clients do not have
// access to the message bean class.
Method[] msgListenerMethods =
msgBeanDesc.getMessageListenerInterfaceMethods(loader);
for(int i = 0; i < msgListenerMethods.length; i++) {
Method next = msgListenerMethods[i];
super.registerTxAttrForMethod(next, MethodDescriptor.EJB_BEAN);
}
// NOTE : No need to register tx attribute for ejbTimeout. It's
// done in BaseContainer intialization.
// Message-driven beans can be timed objects.
// Bootstrap message bean client factory. If the class name is
// specified as a system property, that value takes precedence.
// Otherwise use default client factory. The default is set to
// a client factory that uses the S1AS 7 style JMS connection
// consumer contracts. This will be changed once the Connector 1.5
// implementation is ready.
String factoryClassName = System.getProperty
(MESSAGE_BEAN_CLIENT_FACTORY_PROP,
DEFAULT_MESSAGE_BEAN_CLIENT_FACTORY);
Class clientFactoryClass = Class.forName(factoryClassName);
MessageBeanClientFactory clientFactory = (MessageBeanClientFactory)
clientFactoryClass.newInstance();
_logger.log(Level.FINE, "Using " + factoryClassName +
" for message bean client factory in " + appEJBName_);
// Create message bean pool before calling setup on
// Message-bean client, since pool properties can be retrieved
// through MessageBeanProtocolManager interface.
createMessageBeanPool(msgBeanDesc);
// Set resource limit for message bean listeners created through
// Protocol Manager. For now, just use max pool size. However,
// we might want to bump this up once the ejb timer service is
// integrated.
maxMessageBeanListeners_ = beanPoolDesc_.getMaxPoolSize();
numMessageBeanListeners_ = 0;
messageBeanClient_ =
clientFactory.createMessageBeanClient(msgBeanDesc);
messageBeanClient_.setup(this);
registerMonitorableComponents(msgListenerMethods);
createCallFlowAgent(ComponentType.MDB);
}
catch (Exception ex) {
if (messageBeanClient_ != null) {
messageBeanClient_.close();
}
_logger.log(Level.SEVERE,
"containers.mdb.create_container_exception",
new Object[]{desc.getName(), ex.toString()});
_logger.log(Level.SEVERE, ex.getClass().getName(), ex);
throw ex;
}
|
Methods Summary |
---|
protected ComponentContext | _getContext(Invocation inv)
MessageBeanContextImpl context = null;
try {
context = (MessageBeanContextImpl) messageBeanPool_.getObject(null);
context.setState(INVOKING);
} catch(Exception e) {
throw new EJBException(e);
}
return context;
| public void | activateEJB(java.lang.Object ctx, java.lang.Object instanceKey)
| void | afterBegin(EJBContextImpl context)
// Message-driven Beans cannot implement SessionSynchronization!!
| void | afterCompletion(EJBContextImpl ctx, int status)
// Message-driven Beans cannot implement SessionSynchronization!!
| public void | afterMessageDelivery(com.sun.enterprise.resource.ResourceHandle resourceHandle)
afterMessageDeliveryInternal(resourceHandle);
| private boolean | afterMessageDeliveryInternal(com.sun.enterprise.resource.ResourceHandle resourceHandle)
// return value. assume failure until proven otherwise.
boolean success = false;
Invocation invocation = null;
invocation = (Invocation) invocationManager.getCurrentInvocation();
if (invocation == null) {
_logger.log(Level.SEVERE, "containers.mdb.no_invocation",
new Object[]{appEJBName_, ""});
} else {
MessageBeanContextImpl beanContext =
(MessageBeanContextImpl) invocation.context;
try {
if( invocation.containerStartsTx ) {
// Unregister the session associated with
// the message-driven bean's destination.
unregisterMessageBeanResource(resourceHandle);
}
// counterpart of invocationManager.preInvoke
invocationManager.postInvoke(invocation);
// Commit/Rollback container-managed transaction.
postInvokeTx(invocation);
// Consider successful delivery. Commit failure will be
// checked below.
success = true;
//TODO: Check if Tx existed / committed
statMessageCount++;
} catch(Throwable ce) {
_logger.log(Level.SEVERE,
"containers.mdb.postinvoke_exception",
new Object[]{appEJBName_, ce.toString()});
_logger.log(Level.SEVERE,ce.getClass().getName(), ce);
} finally {
releaseContext(invocation);
}
// Reset original class loader
Utility.setContextClassLoader(invocation.originalContextClassLoader);
if( invocation.exception != null ) {
if( isSystemUncheckedException(invocation.exception) ) {
success = false;
}
// Log system exceptions by default and application exceptions
// only when log level is FINE or higher.
Level exLogLevel =
isSystemUncheckedException(invocation.exception) ?
Level.INFO : Level.FINE;
//START OF IASRI 4660565
_logger.log(exLogLevel,
"containers.mdb.invocation_exception",
new Object[]{appEJBName_,
invocation.exception.toString()});
_logger.log(exLogLevel, invocation.exception.getClass().
getName(), invocation.exception);
}
}
return success;
| public void | appendStats(java.lang.StringBuffer sbuf)
sbuf.append("\nMessageBeanContainer: ")
.append("CreateCount=").append(statCreateCount).append("; ")
.append("RemoveCount=").append(statRemoveCount).append("; ")
.append("MsgCount=").append(statMessageCount).append("; ");
sbuf.append("]");
| void | beforeCompletion(EJBContextImpl context)
// Message-driven beans cannot implement SessionSynchronization!!
| public void | beforeMessageDelivery(java.lang.reflect.Method method, boolean txImported, com.sun.enterprise.resource.ResourceHandle resourceHandle)Actual message delivery happens in three steps :
1) beforeMessageDelivery(Message, MessageListener)
This is our chance to make the message delivery
itself part of the instance's global transaction.
2) onMessage(Message, MessageListener)
This is where the container delegates to the
actual ejb instance's onMessage method.
3) afterMessageDelivery(Message, MessageListener)
Perform transaction cleanup and error handling.
We use the Invocation manager's thread-specific state
to track the invocation across these three calls.
if (containerState != CONTAINER_STARTED) { // i.e. no invocation
String errorMsg = localStrings.getLocalString
("containers.mdb.invocation_closed", appEJBName_ +
": Message-driven bean invocation closed by container",
new Object[] { appEJBName_ });
throw new EJBException(errorMsg);
}
Invocation invocation = new Invocation();
try {
MessageBeanContextImpl context =
(MessageBeanContextImpl) getContext(invocation);
// Set the context class loader here so that message producer will
// have access to application class loader during message processing.
// The previous context class loader will be restored in
// afterMessageDelivery.
invocation.originalContextClassLoader =
Utility.setContextClassLoader(getClassLoader());
invocation.isMessageDriven = true;
invocation.method = method;
context.setState(INVOKING);
invocation.context = context;
invocation.instance = context.getEJB();
invocation.ejb = context.getEJB();
invocation.container = this;
// Message Bean Container only starts a new transaction if
// there is no imported transaction and the message listener
// method has tx attribute TX_REQUIRED or the ejbTimeout has
// tx attribute TX_REQUIRES_NEW/TX_REQUIRED
boolean startTx = false;
if( !txImported ) {
startTx = containerStartsTx(method);
}
// keep track of whether tx was started for later.
invocation.containerStartsTx = startTx;
this.invocationManager.preInvoke(invocation);
if( startTx ) {
// Register the session associated with the message-driven
// bean's destination so the message delivery will be
// part of the container-managed transaction.
registerMessageBeanResource(resourceHandle);
}
preInvokeTx(invocation);
} catch(Throwable c) {
if (containerState != CONTAINER_STARTED ) {
_logger.log(Level.SEVERE,"containers.mdb.preinvoke_exception",
new Object[]{appEJBName_, c.toString()});
_logger.log(Level.SEVERE, c.getClass().getName(), c);
}
invocation.exception = c;
}
| boolean | callEJBTimeout(RuntimeTimerState timerState, EJBTimerService timerService)Override callEJBTimeout from BaseContainer since delivery to
message driven beans is a bit different from session/entity.
boolean redeliver = false;
// There is no resource associated with the delivery of the timeout.
ResourceHandle nullResourceHandle = null;
try {
// Do pre-invoke logic for message bean with tx import = false
// and a null resource handle.
beforeMessageDelivery(ejbTimeoutMethod, false, nullResourceHandle);
// Application must be passed a TimerWrapper.
Object[] args = { new TimerWrapper(timerState.getTimerId(),
timerService) };
deliverMessage(args);
} catch(Throwable t) {
// A runtime exception thrown from ejbTimeout, independent of
// its transactional setting(CMT, BMT, etc.), should result in
// a redelivery attempt. The instance that threw the runtime
// exception will be destroyed, as per the EJB spec.
redeliver = true;
_logger.log(Level.FINE, "ejbTimeout threw Runtime exception", t);
} finally {
if( !isBeanManagedTran && (transactionManager.getStatus() ==
Status.STATUS_MARKED_ROLLBACK) ) {
redeliver = true;
_logger.log(Level.FINE, "ejbTimeout called setRollbackOnly");
}
// Only call postEjbTimeout if there are no errors so far.
if( !redeliver ) {
boolean successfulPostEjbTimeout =
timerService.postEjbTimeout(timerState.getTimerId());
redeliver = !successfulPostEjbTimeout;
}
// afterMessageDelivery takes care of postInvoke and postInvokeTx
// processing. If any portion of that work fails, mark
// timer for redelivery.
boolean successfulAfterMessageDelivery =
afterMessageDeliveryInternal(nullResourceHandle);
if( !redeliver && !successfulAfterMessageDelivery) {
redeliver = true;
}
}
return redeliver;
| private void | cleanupResources()
ASyncClientShutdownTask task = new ASyncClientShutdownTask(appEJBName_,
messageBeanClient_, loader, messageBeanPool_);
int timeout = 0;
try {
timeout = ResourcesUtil.createInstance().getShutdownTimeout();
} catch (Throwable th) {
_logger.log(Level.WARNING, "[MDBContainer] Got exception while trying "
+ " to get shutdown timeout", th);
}
try {
boolean addedAsyncTask = false;
if (timeout > 0) {
try {
ContainerWorkPool.addLast(task);
addedAsyncTask = true;
} catch (Throwable th) {
//Since we got an exception while trying to add the async task
// we will have to do the cleanup in the current thread itself.
addedAsyncTask = false;
_logger.log(Level.WARNING, "[MDBContainer] Got exception while trying "
+ "to add task to ContainerWorkPool. Will execute "
+ "cleanupResources on current thread", th);
}
}
if (addedAsyncTask) {
synchronized (task) {
if (! task.isDone()) {
_logger.log(Level.FINE, "[MDBContainer] "
+ "Going to wait for a maximum of " + timeout + " seconds.");
task.wait(timeout * 1000);
}
if (! task.isDone()) {
_logger.log(Level.WARNING, "[MDBContainer] ASync task has not finished. "
+ "Giving up after " + timeout + " seconds.");
} else {
_logger.log(Level.FINE, "[MDBContainer] ASync task has completed");
}
}
} else {
//Execute in the same thread
_logger.log(Level.FINE, "[MDBContainer] Attempting to do cleanup()in current thread...");
task.run();
_logger.log(Level.WARNING, "[MDBContainer] Current thread done cleanup()... ");
}
} catch (InterruptedException inEx) {
_logger.log(Level.SEVERE, "containers.mdb.cleanup_exception",
new Object[]{appEJBName_, inEx.toString()});
} catch (Exception ex) {
_logger.log(Level.SEVERE, "containers.mdb.cleanup_exception",
new Object[]{appEJBName_, ex.toString()});
}
| private boolean | containerStartsTx(java.lang.reflect.Method method)
int txMode = getTxAttr(method, MethodDescriptor.EJB_BEAN);
return method.equals(ejbTimeoutMethod) ?
( (txMode == TX_REQUIRES_NEW) || (txMode == TX_REQUIRED) )
: (txMode == TX_REQUIRED);
| public EJBObjectImpl | createEJBObjectImpl()
throw new EJBException("No EJBObject for message-driven beans");
| public MessageBeanListener | createMessageBeanListener(com.sun.enterprise.resource.ResourceHandle resource)The following are implementation for methods required by the *
MessageBeanProtocalManager interface. *
boolean resourcesExceeded = false;
synchronized (this) {
if( numMessageBeanListeners_ < maxMessageBeanListeners_ ) {
numMessageBeanListeners_++;
} else {
resourcesExceeded = true;
}
}
if( resourcesExceeded ) {
ResourcesExceededException ree =
new ResourcesExceededException("Message Bean Resources " +
"exceeded for message bean " + appEJBName_);
_logger.log(Level.FINE, "exceeded max of " +
maxMessageBeanListeners_, ree);
throw ree;
}
//
// Message bean context/instance creation is decoupled from
// MessageBeanListener instance creation. This typically means
// the message bean instances are instantiated lazily upon actual
// message delivery. In addition, MessageBeanListener instances
// are not pooled since they are currently very small objects without
// much initialization overhead. This is the simplest approach since
// there is minimal state to track between invocations and upon
// error conditions such as message bean instance failure. However,
// it could be optimized in the following ways :
//
// 1. Implement MessageBeanListener within MessageBeanContextImpl.
// This reduces the number of objects created per thread of delivery.
//
// 2. Associate message bean context/instance with MessageBeanListener
// across invocations. This saves one pool retrieval and one
// pool replacement operation for each invocation.
//
//
return new MessageBeanListenerImpl(this, resource);
| private void | createMessageBeanPool(com.sun.enterprise.deployment.EjbMessageBeanDescriptor descriptor)
beanPoolDesc_ = descriptor.getIASEjbExtraDescriptors().getBeanPool();
if (beanPoolDesc_ == null) {
beanPoolDesc_ = new BeanPoolDescriptor();
}
ServerContext sc = ApplicationServer.getServerContext();
MdbContainer mdbc = ServerBeansFactory.
getConfigBean(sc.getConfigContext()).getMdbContainer();
int maxPoolSize = beanPoolDesc_.getMaxPoolSize();
if (maxPoolSize < 0) {
maxPoolSize =
stringToInt(mdbc.getMaxPoolSize(), appEJBName_, _logger);
}
maxPoolSize = validateValue(maxPoolSize, 1, -1, DEFAULT_MAX_POOL_SIZE,
"max-pool-size", appEJBName_, _logger);
beanPoolDesc_.setMaxPoolSize(maxPoolSize);
int value = beanPoolDesc_.getSteadyPoolSize();
if (value < 0) {
value = stringToInt
(mdbc.getSteadyPoolSize(), appEJBName_, _logger);
}
value = validateValue(value, 0, maxPoolSize, DEFAULT_STEADY_SIZE,
"steady-pool-size", appEJBName_, _logger);
beanPoolDesc_.setSteadyPoolSize(value);
value = beanPoolDesc_.getPoolResizeQuantity();
if (value < 0 ) {
value = stringToInt
(mdbc.getPoolResizeQuantity(), appEJBName_, _logger);
}
value = validateValue(value, 1, maxPoolSize, DEFAULT_RESIZE_QUANTITY,
"pool-resize-quantity", appEJBName_, _logger);
beanPoolDesc_.setPoolResizeQuantity(value);
value = beanPoolDesc_.getPoolIdleTimeoutInSeconds();
if (value <= 0) {
value = stringToInt(mdbc.getIdleTimeoutInSeconds(),
appEJBName_, _logger);
}
value = validateValue(value, MIN_IDLE_TIMEOUT, -1,
DEFAULT_IDLE_TIMEOUT, "idle-timeout-in-seconds",
appEJBName_, _logger);
beanPoolDesc_.setPoolIdleTimeoutInSeconds(value);
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, appEJBName_ +
": Setting message-driven bean pool max-pool-size=" +
beanPoolDesc_.getMaxPoolSize() +
", steady-pool-size=" + beanPoolDesc_.getSteadyPoolSize() +
", pool-resize-quantity=" +
beanPoolDesc_.getPoolResizeQuantity() +
", idle-timeout-in-seconds=" +
beanPoolDesc_.getPoolIdleTimeoutInSeconds());
}
// Create a non-blocking pool of message bean instances.
// The protocol manager implementation enforces a limit
// on message bean resources independent of the pool.
ObjectFactory objFactory = new MessageBeanContextFactory();
messageBeanPool_ = new NonBlockingPool
(appEJBName_,
objFactory,
beanPoolDesc_.getSteadyPoolSize(),
beanPoolDesc_.getPoolResizeQuantity(),
beanPoolDesc_.getMaxPoolSize(),
beanPoolDesc_.getPoolIdleTimeoutInSeconds(),
loader);
registryMediator.registerProvider(messageBeanPool_);
//super.setMonitorOn(mdbc.isMonitoringEnabled());
| private MessageBeanContextImpl | createMessageDrivenEJB()Instantiate and initialize a message-driven bean instance.
Invocation inv = null;
MessageBeanContextImpl context = null;
ClassLoader originalClassLoader = null;
boolean methodCalled = false;
boolean methodCallFailed = false;
try {
// Set application class loader before invoking instance.
originalClassLoader = Utility.setContextClassLoader(getClassLoader());
// create new message-driven ejb
Object ejb = ejbClass.newInstance();
// create MessageDrivenContext and set it in the EJB
context = new MessageBeanContextImpl(ejb, this);
context.setInterceptorInstances(
interceptorManager.createInterceptorInstances());
// java:comp/env lookups are allowed from here on...
inv = new Invocation(ejb, this);
inv.context = context;
inv.isMessageDriven = true;
invocationManager.preInvoke(inv);
if( ejb instanceof MessageDrivenBean ) {
// setMessageDrivenContext will be called without a Tx
// as required by the spec
((MessageDrivenBean)ejb).setMessageDrivenContext(context);
}
// Perform injection right after where setMessageDrivenContext
// would be called. This is important since injection methods
// have the same "operations allowed" permissions as
// setMessageDrivenContext.
injectionManager.injectInstance(ejb, ejbDescriptor, false);
for (Object interceptorInstance : context.getInterceptorInstances()) {
injectionManager.injectInstance(interceptorInstance,
ejbDescriptor, false);
}
// Set flag in context so UserTransaction can
// be used from ejbCreate. Didn't want to add
// a new state to lifecycle since that would
// require either changing lots of code in
// EJBContextImpl or re-implementing all the
// context methods within MessageBeanContextImpl.
context.setContextCalled();
// Call ejbCreate OR @PostConstruct on the bean.
interceptorManager.intercept(
CallbackType.POST_CONSTRUCT, context);
statCreateCount++;
// Set the state to POOLED after ejbCreate so that
// EJBContext methods not allowed will throw exceptions
context.setState(POOLED);
}
catch ( Throwable t ) {
_logger.log(Level.SEVERE,
"containers.mdb.ejb_creation_exception",
new Object[]{appEJBName_, t.toString()});
if (t instanceof InvocationTargetException) {
_logger.log(Level.SEVERE, t.getClass().getName(),
t.getCause());
}
_logger.log(Level.SEVERE, t.getClass().getName(), t);
CreateException ce =
new CreateException("Could not create Message-Driven EJB");
ce.initCause(t);
throw ce;
} finally {
if( originalClassLoader != null ) {
Utility.setContextClassLoader(originalClassLoader);
}
if ( inv != null ) {
invocationManager.postInvoke(inv);
}
}
return context;
| public java.lang.Object | deliverMessage(java.lang.Object[] params)
Invocation invocation = null;
boolean methodCalled = false; //for monitoring
Object result = null;
invocation = (Invocation) invocationManager.getCurrentInvocation();
if (invocation == null && _logger.isLoggable(Level.FINEST)) {
if (containerState != CONTAINER_STARTED) {
_logger.log(Level.FINEST, "No invocation in onMessage " +
" (container closing)");
}
else {
_logger.log(Level.FINEST, "No invocation in onMessage : ");
}
}
if( ( invocation != null ) && ( invocation.exception == null ) ) {
try {
// NOTE : Application classloader already set in
// beforeMessageDelivery
methodCalled = true;
if (ejbMethodStatsManager.isMethodMonitorOn()){
ejbMethodStatsManager.preInvoke(invocation.method);
}
invocation.methodParams = params;
if( isTimedObject() &&
invocation.method.equals(ejbTimeoutMethod) ) {
invocation.beanMethod = invocation.method;
invokeTargetBeanMethod(ejbTimeoutMethod, invocation,
invocation.ejb,
invocation.methodParams, null);
} else {
// invocation.beanMethod is the actual target method from
// the bean class. The bean class is not required to be
// a formal subtype of the message listener interface, so
// we need to be careful to invoke through the bean class
// method itself. This info is also returned from the
// interceptor context info.
invocation.beanMethod = invocation.ejb.getClass().getMethod
(invocation.method.getName(),
invocation.method.getParameterTypes());
result = super.intercept(invocation);
}
} catch(InvocationTargetException ite) {
//
// In EJB 2.1, message listener method signatures do not have
// any restrictions on what kind of exceptions can be thrown.
// This was not the case in J2EE 1.3, since JMS message driven
// beans could only implement
// void javax.jms.MessageListener.onMessage() , which does
// not declare any exceptions.
//
// In the J2EE 1.3 implementation, exceptions were only
// propagated when the message driven bean was not configured
// with CMT/Required transaction mode. This has been changed
// due to the Connector 1.5 integration. Now, all exceptions
// are propagated regardless of the tx mode. (18.2.2)
// Application exceptions are propagated as is, while system
// exceptions are wrapped in an EJBException.
//
// If an exception is thrown and there is a container-started
// transaction, the semantics are the same as for other ejb
// types whose business methods throw an exception.
// Specifically, if the exception thrown is an Application
// exception(defined in 18.2.1), it does not automatically
// result in a rollback of the container-started transaction.
//
Throwable cause = ite.getCause();
// set cause on invocation , rather than the propagated
// EJBException
invocation.exception = cause;
if( isSystemUncheckedException(cause) ) {
EJBException ejbEx = new EJBException
("message-driven bean method " + invocation.method +
" system exception");
ejbEx.initCause(cause);
cause = ejbEx;
}
throw cause;
} catch(Throwable t) {
EJBException ejbEx =
new EJBException("message-bean container dispatch error");
ejbEx.initCause(t);
invocation.exception = ejbEx;
throw ejbEx;
} finally {
if (methodCalled && (ejbMethodStatsManager.isMethodMonitorOn())) {
ejbMethodStatsManager.postInvoke(
invocation.method, invocation.exception);
}
if ( AppVerification.doInstrument() ) {
AppVerification.getInstrumentLogger().doInstrumentForEjb
(getEjbDescriptor(), invocation.method,
invocation.exception);
}
}
} // End if -- invoke instance's onMessage method
else {
if (invocation == null) {
String errorMsg = localStrings.getLocalString
("containers.mdb.invocation_closed",
appEJBName_ + ": Message-driven bean invocation " +
"closed by container", new Object[] { appEJBName_});
throw new EJBException(errorMsg);
}
else {
_logger.log(Level.SEVERE,
"containers.mdb.invocation_exception",
new Object[]{appEJBName_, invocation.exception.toString()});
_logger.log(Level.SEVERE, invocation.exception.getClass().
getName(), invocation.exception);
EJBException ejbEx = new EJBException();
ejbEx.initCause(invocation.exception);
throw ejbEx;
}
}
return result;
| public void | destroyMessageBeanListener(MessageBeanListener listener)
synchronized (this) {
numMessageBeanListeners_--;
}
| public void | doAfterApplicationDeploy()Called when the application containing this message-bean
has successfully deployed.
super.doAfterApplicationDeploy();
// Start delivery of messages to message bean instances.
try {
messageBeanClient_.start();
}
catch(Exception e) {
_logger.log(Level.SEVERE,
"containers.mdb.start_message_delivery_exception",
new Object[]{appEJBName_, e.toString()});
_logger.log(Level.SEVERE, e.getClass().getName(), e);
}
| void | forceDestroyBean(EJBContextImpl sc)Force destroy the EJB. Called from postInvokeTx.
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 ( sc.getState() == DESTROYED )
return;
// mark context as destroyed
sc.setState(DESTROYED);
messageBeanPool_.destroyObject(sc);
| public long | getCreateCount()
return statCreateCount;
| public EJBObjectImpl | getEJBObjectImpl(byte[] instanceKey)
throw new EJBException("No EJBObject for message-driven beans");
| public long | getMessageCount()
return statMessageCount;
| public java.lang.String | getMonitorAttributeValues()
StringBuffer sbuf = new StringBuffer();
sbuf.append("MESSAGEDRIVEN ");
sbuf.append(appEJBName_);
sbuf.append(messageBeanPool_.getAllAttrValues());
sbuf.append("]");
return sbuf.toString();
| public com.sun.enterprise.deployment.runtime.BeanPoolDescriptor | getPoolDescriptor()
return beanPoolDesc_;
| public long | getRemoveCount()
return statRemoveCount;
| public boolean | isDeliveryTransacted(java.lang.reflect.Method method)
return containerStartsTx(method);
| public void | onShutdown()Called when server instance is shuting down
_logger.log(Level.FINE,
"containers.mdb.shutdown_cleanup_start", appEJBName_);
setStoppedState();
monitorOn = false;
cleanupResources();
_logger.log(Level.FINE,
"containers.mdb.shutdown_cleanup_end", appEJBName_);
| public boolean | passivateEJB(ComponentContext context)
return false;
| public void | postInvoke(Invocation inv)
throw new EJBException("postInvoke(Invocation) not supported " +
"in message-driven bean container");
| public void | preInvoke(Invocation inv)
throw new EJBException("preInvoke(Invocation) not supported");
| private void | registerMessageBeanResource(com.sun.enterprise.resource.ResourceHandle resourceHandle)Make the work performed by a message-bean instance's
associated XA resource part of any global transaction
if( resourceHandle != null ) {
Switch theSwitch = Switch.getSwitch();
PoolManager poolMgr = theSwitch.getPoolManager();
poolMgr.registerResource(resourceHandle);
}
| protected void | registerMonitorableComponents(java.lang.reflect.Method[] msgListenerMethods)
registryMediator.registerProvider(this);
super.registerMonitorableComponents();
super.populateMethodMonitorMap(msgListenerMethods);
_logger.log(Level.FINE, "[Entity Container] registered monitorable");
| public void | releaseContext(Invocation inv)Return instance to a pooled state.
MessageBeanContextImpl beanContext = (MessageBeanContextImpl)
inv.context;
if( beanContext.getState() == DESTROYED ) {
return;
}
beanContext.setState(POOLED);
// Message-driven beans can't have transactions across invocations.
beanContext.setTransaction(null);
// Update last access time so pool's time-based logic will work best
beanContext.touch();
messageBeanPool_.returnObject(beanContext);
| void | removeBean(EJBLocalRemoteObject ejbo, java.lang.reflect.Method removeMethod, boolean local)
throw new EJBException("not used in message-driven beans");
| public void | setEJBHome(EJBHome ejbHome)
throw new Exception("Can't set EJB Home on Message-driven bean");
| protected static int | stringToInt(java.lang.String val, java.lang.String appName, java.util.logging.Logger logger)
int value = -1;
try {
value = Integer.parseInt(val);
} catch (Exception e) {
_logger.log(Level.WARNING,"containers.mdb.invalid_value" ,
new Object[]{appName, new Integer(val) , e.toString(),
new Integer(0)} );
_logger.log(Level.WARNING, "", e);
}
return value;
| public void | undeploy()
// This will cause all new invocations to be rejected.
super.setUndeployedState();
_logger.log(Level.FINE, "containers.mdb.undeploy", appEJBName_);
cleanupResources();
super.undeploy();
| private void | unregisterMessageBeanResource(com.sun.enterprise.resource.ResourceHandle resourceHandle)
// resource handle may be null if preInvokeTx error caused
// ResourceAllocator.destroyResource()
if (resourceHandle != null) {
Switch theSwitch = Switch.getSwitch();
PoolManager poolMgr = theSwitch.getPoolManager();
poolMgr.unregisterResource(resourceHandle, XAResource.TMSUCCESS);
}
| public boolean | userTransactionMethodsAllowed(ComponentInvocation inv)
boolean utMethodsAllowed = false;
if( isBeanManagedTran ) {
if( inv instanceof Invocation ) {
Invocation i = (Invocation) inv;
EJBContextImpl mdc = (EJBContextImpl) i.context;
utMethodsAllowed = (mdc.isUnitialized() || mdc.isInEjbRemove())
? false : true;
}
}
return utMethodsAllowed;
| protected int | validateValue(int value, int lowLimit, int highLimit, int deft, java.lang.String emsg, java.lang.String appName, java.util.logging.Logger logger)
if (value < lowLimit ) {
_logger.log(Level.WARNING,"containers.mdb.invalid_value" ,
new Object[]{appName, new Integer(value) , emsg ,
new Integer(lowLimit)} );
value = deft;
}
if ((highLimit >= 0) && (value > highLimit)) {
_logger.log(Level.WARNING,"containers.mdb.invalid_value" ,
new Object[]{appName, new Integer(value) , emsg ,
new Integer(highLimit)} );
value = highLimit;
}
return value;
|
|