001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.jms.client.container;
023:
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.Set;
027:
028: import org.jboss.aop.advice.Interceptor;
029: import org.jboss.aop.joinpoint.Invocation;
030: import org.jboss.aop.joinpoint.MethodInvocation;
031: import org.jboss.jms.client.Lifecycle;
032: import org.jboss.jms.container.Container;
033:
034: /**
035: * An interceptor for checking closed state. It waits for
036: * other invocations to complete allowing the close.
037: *
038: * @author <a href="mailto:adrian@jboss.org>Adrian Brock</a>
039: * @version $Revision: 57195 $
040: */
041: public class ClosedInterceptor implements Interceptor {
042: // Constants -----------------------------------------------------
043:
044: /** Not closed */
045: private static final int NOT_CLOSED = 0;
046:
047: /** Closing */
048: private static final int IN_CLOSING = 1;
049:
050: /** Closing */
051: private static final int CLOSING = 2;
052:
053: /** Performing the close */
054: private static final int IN_CLOSE = 3;
055:
056: /** Closed */
057: private static final int CLOSED = -1;
058:
059: // Attributes ----------------------------------------------------
060:
061: /** The state of the object */
062: private int state = NOT_CLOSED;
063:
064: /** The inuse count */
065: private int inuseCount = 0;
066:
067: // Static --------------------------------------------------------
068:
069: // Constructors --------------------------------------------------
070:
071: // Public --------------------------------------------------------
072:
073: // Interceptor implementation -----------------------------------
074:
075: public String getName() {
076: return "ClosedInterceptor";
077: }
078:
079: public Object invoke(Invocation invocation) throws Throwable {
080: String methodName = ((MethodInvocation) invocation).getMethod()
081: .getName();
082: boolean isClosing = methodName.equals("closing");
083: boolean isClose = methodName.equals("close");
084:
085: if (isClosing) {
086: if (checkClosingAlreadyDone())
087: return null;
088: } else if (isClose) {
089: if (checkCloseAlreadyDone())
090: return null;
091: } else
092: inuse();
093:
094: if (isClosing)
095: maintainRelatives(invocation);
096:
097: try {
098: return invocation.invokeNext();
099: } finally {
100: if (isClosing)
101: closing();
102: else if (isClose)
103: closed();
104: else
105: done();
106: }
107: }
108:
109: // Protected ------------------------------------------------------
110:
111: /**
112: * Check the closing notification has not already been done
113: *
114: * @return true when already closing or closed
115: */
116: protected synchronized boolean checkClosingAlreadyDone()
117: throws Throwable {
118: if (state != NOT_CLOSED)
119: return true;
120: state = IN_CLOSING;
121: return false;
122: }
123:
124: /**
125: * Closing the object
126: */
127: protected synchronized void closing() throws Throwable {
128: state = CLOSING;
129: }
130:
131: /**
132: * Check the close has not already been done and
133: * wait for all invocations to complete
134: *
135: * @return true when already closed
136: */
137: protected synchronized boolean checkCloseAlreadyDone()
138: throws Throwable {
139: if (state != CLOSING)
140: return true;
141: while (inuseCount > 0)
142: wait();
143: state = IN_CLOSE;
144: return false;
145: }
146:
147: /**
148: * Closed the object
149: */
150: protected synchronized void closed() throws Throwable {
151: state = CLOSED;
152: }
153:
154: /**
155: * Mark the object as inuse
156: */
157: protected synchronized void inuse() throws Throwable {
158: if (state != NOT_CLOSED)
159: throw new IllegalStateException("Already closed");
160: ++inuseCount;
161: }
162:
163: /**
164: * Mark the object as no longer inuse
165: */
166: protected synchronized void done() throws Throwable {
167: if (--inuseCount == 0)
168: notifyAll();
169: }
170:
171: /**
172: * Close children and remove from parent
173: *
174: * @param invocation the invocation
175: */
176: protected void maintainRelatives(Invocation invocation) {
177: // We use a clone to avoid a deadlock where requests
178: // are made to close parent and child concurrently
179: Container container = Container.getContainer(invocation);
180: Set clone = null;
181: Set children = container.getChildren();
182: synchronized (children) {
183: clone = new HashSet(children);
184: }
185:
186: // Cycle through the children this will do a depth
187: // first close
188: for (Iterator i = clone.iterator(); i.hasNext();) {
189: Container childContainer = (Container) i.next();
190: Lifecycle child = (Lifecycle) childContainer.getProxy();
191: try {
192: child.closing();
193: child.close();
194: } catch (Throwable ignored) {
195: // Add a log interceptor to the child if you want the error
196: }
197: }
198:
199: // Remove from the parent
200: Container parent = container.getParent();
201: if (parent != null)
202: parent.removeChild(container);
203: }
204:
205: // Package Private ------------------------------------------------
206:
207: // Private --------------------------------------------------------
208:
209: // Inner Classes --------------------------------------------------
210:
211: }
|