| Method from org.jboss.ejb.plugins.CleanShutdownInterceptor Detail: |
protected void containerIsAboutToStop() {
// Distinction between between JMX proxies and underlying services seems
// to lead to a 2nd STOPPING event; ignore it or we get an NPE
if (ejbModule == null)
{
log.debug("Received STOPPING notification after container already set to null; ignoring");
return;
}
log.debug ("Container about to stop: disabling HA-RMI access to bean from interceptor");
// This is bad: we should have some kind of code (manager) associated
// with this ejbModule. We mimic this by electing the first ProxyFactoryHA
// as a manager
//
boolean iAmTheManager = !Boolean.TRUE.equals (ejbModule.getModuleData ("ShutdownInterceptorElected"));
if (iAmTheManager)
{
ejbModule.putModuleData ("ShutdownInterceptorElected", Boolean.TRUE);
if (isDebugEnabled) log.debug ("Container is about to stop and I am the manager of the first step: blocking remote calls");
// in a first step, all interceptors must refuse/redirect remote invocations
//
Collection containers = ejbModule.getContainers ();
Iterator containersIter = containers.iterator ();
while (containersIter.hasNext ())
{
Container otherContainer = (Container)containersIter.next ();
CleanShutdownInterceptor inter = (CleanShutdownInterceptor)
ejbModule.getModuleData ("CleanShutDownInterceptor-" + otherContainer.getServiceName ().toString ());
if (inter == null)
{
log.debug ("Found an EJB that doesnt have a clean-shutdown interceptor: " + otherContainer.getJmxName ());
}
else
{
inter.onlyAllowLocalInvocations ();
}
}
}
else
{
if (isDebugEnabled) log.debug ("Container is about to stop but I am not the manager: I don't manage the first step of the process.");
}
// in a second step, all container, manager or not, will wait that no more invocation
// are running through
// The cycling around other interceptor is managed by the JMX callbacks, not by us
//
waitForNoMoreInvocations ();
}
|
public void create() throws Exception {
super.create ();
this.allowInvocations = false;
this.allowRemoteInvocations = false;
this.isDebugEnabled = log.isDebugEnabled ();
ejbModuleName = ejbModule.getServiceName().toString();
// we register our inner-class to retrieve STATE notifications from our container
//
AttributeChangeNotificationFilter filter = new AttributeChangeNotificationFilter ();
filter.enableAttribute ("State");
this.container.getServer ().
addNotificationListener (this.container.getEjbModule ().getServiceName (),
new CleanShutdownInterceptor.StateChangeListener (),
filter,
null);
// we need a way to find all CleanShutDownInterceptor of an EjbModule
//
ejbModule.putModuleData ("CleanShutDownInterceptor-" + this.container.getServiceName ().toString (), this);
}
|
public void destroy() {
super.destroy ();
this.log.debug ("Destroying container " + container.getJmxName ().toString () + ". " +
this.runningHomeInvocations + " current home invocations and " +
this.runningInvocations + " current remote invocations.");
forbidInvocations() ;
}
|
protected void forbidInvocations() {
this.allowInvocations = false;
purgeRunningInvocations();
}
|
public Container getContainer() {
return this.container;
}
|
protected String getOrigin(Invocation mi) {
String value = (String)currentModule.get ();
if (log.isTraceEnabled())
log.trace ("GET_ORIGIN: " + value + " in " + this.container.getServiceName ().toString ());
return value;
}
|
public Object invoke(Invocation mi) throws Exception {
if (this.allowInvocations)
{
String origin = getOrigin (mi);
boolean isAppLocalCall = ejbModuleName.equals (origin);
if (!this.allowRemoteInvocations && !isAppLocalCall)
// it is a remote call and they are currently forbidden!
//
{
if (isDebugEnabled) log.debug ("Refusing a remote invocation");
throw new GenericClusteringException (GenericClusteringException.COMPLETED_NO,
"This application does not accept remote calls any more");
}
// we need to acquire the read lock. If we cannot directly, it means
// that the stop/destroy call has gotten the write lock in the meantime
//
try
{
if (!isAppLocalCall) // we only consider remote calls = > every local originates from a remote!
{
if (!rwLock.readLock ().attempt (readAcquireTimeMs))
throw new GenericClusteringException (GenericClusteringException.COMPLETED_NO,
"Container is shuting down on this node (timeout)");
}
}
catch (java.lang.InterruptedException ie)
{
throw new GenericClusteringException (GenericClusteringException.COMPLETED_NO,
"Container is shuting down on this node");
}
runningInvocations++;
try
{
if (!isAppLocalCall)
setOrigin (mi);
return this.getNext ().invoke (mi);
}
catch (GenericClusteringException gce)
{
// a gce exception has be thrown somewhere else: we need to modify its flag
// and forward it. We could add optimisations at this level by having some
// "idempotent" flag at the container level
//
gce.setCompletionStatus (gce.COMPLETED_MAYBE);
throw gce;
}
finally
{
if (!isAppLocalCall)
revertOrigin (mi, origin);
runningInvocations--;
if (!isAppLocalCall) // we only consider remote calls = > every local originates from a remote!
rwLock.readLock ().release ();
}
}
else
throw new GenericClusteringException (GenericClusteringException.COMPLETED_NO,
"Container is shuting down on this node");
}
|
public Object invokeHome(Invocation mi) throws Exception {
if (this.allowInvocations)
{
String origin = getOrigin (mi);
boolean isAppLocalCall = ejbModuleName.equals (origin);
if (!this.allowRemoteInvocations && !isAppLocalCall)
// it is a remote call and they are currently forbidden!
//
{
if (isDebugEnabled) log.debug ("Refusing a remote home invocation. here= " + ejbModuleName + "; Origin= " + origin);
throw new GenericClusteringException (GenericClusteringException.COMPLETED_NO,
"This application does not accept remote calls any more");
}
// we need to acquire the read lock. If we cannot directly, it means
// that the stop/destroy call has gotten the write lock in the meantime
//
try
{
if (!isAppLocalCall) // we only consider remote calls = > every local originates from a remote!
{
if (!rwLock.readLock ().attempt (readAcquireTimeMs))
throw new GenericClusteringException (GenericClusteringException.COMPLETED_NO,
"Container is shuting down on this node (timeout)");
}
}
catch (java.lang.InterruptedException ie)
{
throw new GenericClusteringException (GenericClusteringException.COMPLETED_NO,
"Container is shuting down on this node");
}
runningHomeInvocations++;
try
{
if (!isAppLocalCall)
setOrigin (mi);
return this.getNext ().invokeHome (mi);
}
catch (GenericClusteringException gce)
{
// a gce exception has be thrown somewhere else: we need to modify its flag
// and forward it. We could add optimisations at this level by having some
// "idempotent" flag at the container level
//
gce.setCompletionStatus (gce.COMPLETED_MAYBE);
throw gce;
}
finally
{
if (!isAppLocalCall)
revertOrigin (mi, origin);
runningHomeInvocations--;
if (!isAppLocalCall) // we only consider remote calls = > every local originates from a remote!
rwLock.readLock ().release ();
}
}
else
throw new GenericClusteringException (GenericClusteringException.COMPLETED_NO,
"Container is shuting down on this node");
}
|
public void onlyAllowLocalInvocations() {
if (isDebugEnabled) log.debug ("Only allow local invocation from now on: " + this.container.getServiceName ().toString ());
this.allowRemoteInvocations = false;
}
|
protected void purgeRunningInvocations() {
try
{
if (this.rwLock.writeLock ().attempt (shutdownTimeout))
this.rwLock.writeLock ().release ();
else
log.info ("Possible running invocations not terminated " +
"while leaving the container. Home: " + runningHomeInvocations +
". Remote: " + runningInvocations + ".");
}
catch (Exception e)
{
log.info ("Exception while waiting for running invocations " +
"to leave container. Home: " + runningHomeInvocations +
". Remote: " + runningInvocations + ".", e);
}
finally
{
}
}
|
protected void revertOrigin(Invocation mi,
String origin) {
if (log.isTraceEnabled()) log.trace ("Crossing ejbModule border from " + this.ejbModuleName + " to " + origin);
currentModule.set (origin);
}
|
public void setContainer(Container con) {
this.container = con;
if (con != null)
this.ejbModule = con.getEjbModule ();
else
this.ejbModule = null;
}
This callback is set by the container so that the plugin may access it |
protected void setOrigin(Invocation mi) {
currentModule.set (this.ejbModuleName);
}
|
public void start() throws Exception {
super.start();
this.allowInvocations = true;
this.allowRemoteInvocations = true;
}
|
public void stop() {
super.stop ();
this.log.debug ("Stopping container " + container.getJmxName () + ". " +
this.runningHomeInvocations + " current home invocations and " +
this.runningInvocations + " current remote invocations.");
forbidInvocations ();
}
|
public void waitForNoMoreInvocations() {
this.log.debug ("Waiting that the container " + container.getJmxName () + " finishes its running invocations. " +
this.runningHomeInvocations + " current home invocations and " +
this.runningInvocations + " current remote invocations.");
purgeRunningInvocations ();
if (isDebugEnabled) log.debug ("... Done: no more remote invocations currently running in this container.");
}
|