2626package com .rabbitmq .client .impl ;
2727
2828import java .io .IOException ;
29+ import java .util .concurrent .TimeoutException ;
2930
31+ import com .rabbitmq .client .AlreadyClosedException ;
3032import com .rabbitmq .client .Command ;
3133import com .rabbitmq .client .Connection ;
3234import com .rabbitmq .client .ShutdownSignalException ;
3335import com .rabbitmq .utility .BlockingValueOrException ;
34- import com .rabbitmq .utility .SingleShotLinearTimer ;
3536
3637/**
3738 * Base class modelling an AMQ channel. Subclasses implement close()
@@ -53,9 +54,9 @@ public abstract class AMQChannel {
5354
5455 /** The current outstanding RPC request, if any. (Could become a queue in future.) */
5556 public RpcContinuation _activeRpc = null ;
56-
57- /** Indicates whether this channel is in a state to handle further activity. */
58- public volatile boolean _isOpen = true ;
57+
58+ /** Reason for closing the channel, null if still open */
59+ public volatile ShutdownSignalException _cause ;
5960
6061 /**
6162 * Construct a channel on the given connection, with the given channel number.
@@ -117,6 +118,10 @@ public AMQCommand exnWrappingRpc(Method m)
117118 {
118119 try {
119120 return rpc (m );
121+ } catch (AlreadyClosedException ace ) {
122+ // Do not wrap it since it means that connection/channel
123+ // was closed in some action in the past
124+ throw ace ;
120125 } catch (ShutdownSignalException ex ) {
121126 throw wrap (ex );
122127 }
@@ -160,21 +165,36 @@ public synchronized void transmitAndEnqueue(Method m, RpcContinuation k)
160165 transmit (m );
161166 }
162167
163- public synchronized RpcContinuation nextOutstandingRpc () {
168+ public synchronized RpcContinuation nextOutstandingRpc ()
169+ {
164170 RpcContinuation result = _activeRpc ;
165171 _activeRpc = null ;
166172 return result ;
167173 }
168174
169- public boolean isOpen () {
170- return _isOpen ;
175+ /**
176+ * Public API - Indicates whether this channel is in an open state
177+ * @return true if channel is open, false otherwise
178+ */
179+ public boolean isOpen ()
180+ {
181+ return _cause == null ;
182+ }
183+
184+ /**
185+ * Public API - Get the reason for closing the channel
186+ * @return object having information about the shutdown, or null if still open
187+ */
188+ public ShutdownSignalException getCloseReason ()
189+ {
190+ return _cause ;
171191 }
172192
173193 public void ensureIsOpen ()
174- throws IllegalStateException
194+ throws AlreadyClosedException
175195 {
176196 if (!isOpen ()) {
177- throw new IllegalStateException ("Attempt to use closed channel" );
197+ throw new AlreadyClosedException ("Attempt to use closed channel" );
178198 }
179199 }
180200
@@ -211,34 +231,11 @@ public synchronized void rpc(Method m, RpcContinuation k)
211231 public AMQCommand quiescingRpc (Method m ,
212232 int timeoutMillisec ,
213233 final AMQCommand timeoutReply )
214- throws IOException , ShutdownSignalException
234+ throws IOException , ShutdownSignalException , TimeoutException
215235 {
216- SimpleBlockingRpcContinuation k = new SimpleBlockingRpcContinuation ();
236+ TimeoutBlockingRpcContinuation k = new TimeoutBlockingRpcContinuation ();
217237 transmitAndEnqueue (m , k );
218- if (timeoutMillisec != 0 ) {
219- SingleShotLinearTimer timer = new SingleShotLinearTimer ();
220-
221- Runnable task = new Runnable () {
222- public void run () {
223- // Timed out waiting for reply.
224- // Simulate a reply.
225- // TODO: Warn the user somehow??
226- try {
227- handleCompleteInboundCommand (timeoutReply );
228- } catch (IOException ioe ) {
229- // Ignore.
230- }
231- }
232- };
233- timer .schedule (task , timeoutMillisec );
234- try {
235- return k .getReply ();
236- } finally {
237- timer .cancel ();
238- }
239- } else {
240- return k .getReply ();
241- }
238+ return k .getReply (timeoutMillisec );
242239 }
243240
244241 /**
@@ -253,15 +250,15 @@ public void run() {
253250 @ Override public String toString () {
254251 return "AMQChannel(" + _connection + "," + _channelNumber + ")" ;
255252 }
256-
253+
257254 /**
258255 * Protected API - respond, in the driver thread, to a {@link ShutdownSignalException}.
259256 * @param signal the signal to handle
260257 */
261258 public void processShutdownSignal (ShutdownSignalException signal ) {
262259 synchronized (this ) {
263260 ensureIsOpen (); // invariant: we should never be shut down more than once per instance
264- _isOpen = false ;
261+ _cause = signal ;
265262 }
266263 RpcContinuation k = nextOutstandingRpc ();
267264 if (k != null ) {
@@ -309,4 +306,14 @@ public AMQCommand transformReply(AMQCommand command) {
309306 return command ;
310307 }
311308 }
309+
310+ public static class TimeoutBlockingRpcContinuation
311+ extends SimpleBlockingRpcContinuation
312+ {
313+ public AMQCommand getReply (int timeout )
314+ throws ShutdownSignalException , TimeoutException
315+ {
316+ return _blocker .uninterruptibleGetValue (timeout );
317+ }
318+ }
312319}
0 commit comments