/** * Handles incoming control commands on channel zero. * * @see ChannelN#processAsync */ @SuppressWarnings("unused") public boolean processControlCommand(Command c) throws IOException { // Similar trick to ChannelN.processAsync used here, except // we're interested in whole-connection quiescing. // See the detailed comments in ChannelN.processAsync. Method method = c.getMethod(); if (isOpen()) { if (method instanceof AMQP.Connection.Close) { handleConnectionClose(c); return true; } else if (method instanceof AMQP.Connection.Blocked) { AMQP.Connection.Blocked blocked = (AMQP.Connection.Blocked) method; try { for (BlockedListener l : this.blockedListeners) { l.handleBlocked(blocked.getReason()); } } catch (Throwable ex) { getExceptionHandler().handleBlockedListenerException(this, ex); } return true; } else if (method instanceof AMQP.Connection.Unblocked) { try { for (BlockedListener l : this.blockedListeners) { l.handleUnblocked(); } } catch (Throwable ex) { getExceptionHandler().handleBlockedListenerException(this, ex); } return true; } else { return false; } } else { if (method instanceof AMQP.Connection.Close) { // Already shutting down, so just send back a CloseOk. try { _channel0.quiescingTransmit(new AMQP.Connection.CloseOk.Builder().build()); } catch (IOException ignored) { } // ignore return true; } else if (method instanceof AMQP.Connection.CloseOk) { // It's our final "RPC". Time to shut down. _running = false; // If Close was sent from within the MainLoop we // will not have a continuation to return to, so // we treat this as processed in that case. return !_channel0.isOutstandingRpc(); } else { // Ignore all others. return true; } } }
/** * Protected API - Close this connection with the given code, message, source and timeout value * for all the close operations to complete. Specifies if any encountered exceptions should be * ignored. */ public void close( int closeCode, String closeMessage, boolean initiatedByApplication, Throwable cause, int timeout, boolean abort) throws IOException { boolean sync = !(Thread.currentThread() == mainLoopThread); try { AMQP.Connection.Close reason = new AMQP.Connection.Close.Builder().replyCode(closeCode).replyText(closeMessage).build(); final ShutdownSignalException sse = startShutdown(reason, initiatedByApplication, cause, true); if (sync) { BlockingRpcContinuation<AMQCommand> k = new BlockingRpcContinuation<AMQCommand>() { @Override public AMQCommand transformReply(AMQCommand command) { AMQConnection.this.finishShutdown(sse); return command; } }; _channel0.quiescingRpc(reason, k); k.getReply(timeout); } else { _channel0.quiescingTransmit(reason); } } catch (TimeoutException tte) { if (!abort) { ShutdownSignalException sse = new ShutdownSignalException(true, true, null, this); sse.initCause(cause); throw sse; } } catch (ShutdownSignalException sse) { if (!abort) throw sse; } catch (IOException ioe) { if (!abort) throw ioe; } finally { if (sync) _frameHandler.close(); } }
@SuppressWarnings("unused") public void handleConnectionClose(Command closeCommand) { ShutdownSignalException sse = shutdown(closeCommand.getMethod(), false, null, _inConnectionNegotiation); try { _channel0.quiescingTransmit(new AMQP.Connection.CloseOk.Builder().build()); } catch (IOException ignored) { } // ignore _brokerInitiatedShutdown = true; SocketCloseWait scw = new SocketCloseWait(sse); // if shutdown executor is configured, use it. Otherwise // execut socket close monitor the old fashioned way. // see rabbitmq/rabbitmq-java-client#91 if (shutdownExecutor != null) { shutdownExecutor.execute(scw); } else { final String name = "RabbitMQ connection shutdown monitor " + getHostAddress() + ":" + getPort(); Thread waiter = Environment.newThread(threadFactory, scw, name); waiter.start(); } }