| ClosedInterceptor.java |
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.jms.client.container;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.joinpoint.Invocation;
import org.jboss.aop.joinpoint.MethodInvocation;
import org.jboss.jms.client.Lifecycle;
import org.jboss.jms.container.Container;
/**
* An interceptor for checking closed state. It waits for
* other invocations to complete allowing the close.
*
* @author <a href="mailto:adrian@jboss.org>Adrian Brock</a>
* @version $Revision: 1.4 $
*/
public class ClosedInterceptor
implements Interceptor
{
// Constants -----------------------------------------------------
/** Not closed */
private static final int NOT_CLOSED = 0;
/** Closing */
private static final int IN_CLOSING = 1;
/** Closing */
private static final int CLOSING = 2;
/** Performing the close */
private static final int IN_CLOSE = 3;
/** Closed */
private static final int CLOSED = -1;
// Attributes ----------------------------------------------------
/** The state of the object */
private int state = NOT_CLOSED;
/** The inuse count */
private int inuseCount = 0;
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
// Interceptor implementation -----------------------------------
public String getName()
{
return "ClosedInterceptor";
}
public Object invoke(Invocation invocation) throws Throwable
{
String methodName = ((MethodInvocation) invocation).getMethod().getName();
boolean isClosing = methodName.equals("closing");
boolean isClose = methodName.equals("close");
if (isClosing)
{
if (checkClosingAlreadyDone())
return null;
}
else if (isClose)
{
if(checkCloseAlreadyDone())
return null;
}
else
inuse();
if (isClosing)
maintainRelatives(invocation);
try
{
return invocation.invokeNext();
}
finally
{
if (isClosing)
closing();
else if (isClose)
closed();
else
done();
}
}
// Protected ------------------------------------------------------
/**
* Check the closing notification has not already been done
*
* @return true when already closing or closed
*/
protected synchronized boolean checkClosingAlreadyDone()
throws Throwable
{
if (state != NOT_CLOSED)
return true;
state = IN_CLOSING;
return false;
}
/**
* Closing the object
*/
protected synchronized void closing()
throws Throwable
{
state = CLOSING;
}
/**
* Check the close has not already been done and
* wait for all invocations to complete
*
* @return true when already closed
*/
protected synchronized boolean checkCloseAlreadyDone()
throws Throwable
{
if (state != CLOSING)
return true;
while (inuseCount > 0)
wait();
state = IN_CLOSE;
return false;
}
/**
* Closed the object
*/
protected synchronized void closed()
throws Throwable
{
state = CLOSED;
}
/**
* Mark the object as inuse
*/
protected synchronized void inuse()
throws Throwable
{
if (state != NOT_CLOSED)
throw new IllegalStateException("Already closed");
++inuseCount;
}
/**
* Mark the object as no longer inuse
*/
protected synchronized void done()
throws Throwable
{
if (--inuseCount == 0)
notifyAll();
}
/**
* Close children and remove from parent
*
* @param invocation the invocation
*/
protected void maintainRelatives(Invocation invocation)
{
// We use a clone to avoid a deadlock where requests
// are made to close parent and child concurrently
Container container = Container.getContainer(invocation);
Set clone = null;
Set children = container.getChildren();
synchronized (children)
{
clone = new HashSet(children);
}
// Cycle through the children this will do a depth
// first close
for (Iterator i = clone.iterator(); i.hasNext();)
{
Container childContainer = (Container) i.next();
Lifecycle child = (Lifecycle) childContainer.getProxy();
try
{
child.closing();
child.close();
}
catch (Throwable ignored)
{
// Add a log interceptor to the child if you want the error
}
}
// Remove from the parent
Container parent = container.getParent();
if (parent != null)
parent.removeChild(container);
}
// Package Private ------------------------------------------------
// Private --------------------------------------------------------
// Inner Classes --------------------------------------------------
}
| ClosedInterceptor.java |