@Override
 public final Connection createConnection() throws AmqpException {
   Assert.state(
       !this.stopped,
       "The ApplicationContext is closed and the ConnectionFactory can no longer create connections.");
   synchronized (this.connectionMonitor) {
     if (this.cacheMode == CacheMode.CHANNEL) {
       if (this.connection == null) {
         this.connection = new ChannelCachingConnectionProxy(super.createBareConnection());
         // invoke the listener *after* this.connection is assigned
         getConnectionListener().onCreate(connection);
         this.checkoutPermits.put(this.connection, new Semaphore(this.channelCacheSize));
       }
       return this.connection;
     } else if (this.cacheMode == CacheMode.CONNECTION) {
       ChannelCachingConnectionProxy connection = null;
       while (connection == null && !this.idleConnections.isEmpty()) {
         connection = this.idleConnections.poll();
         if (connection != null) {
           if (!connection.isOpen()) {
             if (logger.isDebugEnabled()) {
               logger.debug("Removing closed connection '" + connection + "'");
             }
             connection.notifyCloseIfNecessary();
             this.openConnections.remove(connection);
             this.openConnectionNonTransactionalChannels.remove(connection);
             this.openConnectionTransactionalChannels.remove(connection);
             this.checkoutPermits.remove(connection);
             connection = null;
           }
         }
       }
       if (connection == null) {
         connection = new ChannelCachingConnectionProxy(super.createBareConnection());
         getConnectionListener().onCreate(connection);
         if (logger.isDebugEnabled()) {
           logger.debug("Adding new connection '" + connection + "'");
         }
         this.openConnections.add(connection);
         this.openConnectionNonTransactionalChannels.put(
             connection, new LinkedList<ChannelProxy>());
         this.openConnectionTransactionalChannels.put(connection, new LinkedList<ChannelProxy>());
         this.checkoutPermits.put(connection, new Semaphore(this.channelCacheSize));
       } else {
         if (logger.isDebugEnabled()) {
           logger.debug("Obtained connection '" + connection + "' from cache");
         }
       }
       return connection;
     }
   }
   return null;
 }
 /**
  * Close the connection(s). This will impact any in-process operations. New connection(s) will be
  * created on demand after this method returns. This might be used to force a reconnect to the
  * primary broker after failing over to a secondary broker.
  */
 public void resetConnection() {
   synchronized (this.connectionMonitor) {
     if (connection != null) {
       this.connection.destroy();
       this.checkoutPermits.remove(this.connection);
       this.connection = null;
     }
     for (ChannelCachingConnectionProxy connection : this.openConnections) {
       connection.destroy();
       this.checkoutPermits.remove(connection);
     }
     this.openConnections.clear();
     this.idleConnections.clear();
     this.openConnectionNonTransactionalChannels.clear();
     this.openConnectionTransactionalChannels.clear();
   }
 }
 private Channel createBareChannel(
     ChannelCachingConnectionProxy connection, boolean transactional) {
   if (this.cacheMode == CacheMode.CHANNEL) {
     if (this.connection == null || !this.connection.isOpen()) {
       synchronized (this.connectionMonitor) {
         if (this.connection != null && !this.connection.isOpen()) {
           this.connection.notifyCloseIfNecessary();
           this.checkoutPermits.remove(this.connection);
         }
         if (this.connection == null || !this.connection.isOpen()) {
           this.connection = null;
           createConnection();
         }
       }
     }
     return doCreateBareChannel(this.connection, transactional);
   } else if (this.cacheMode == CacheMode.CONNECTION) {
     if (!connection.isOpen()) {
       synchronized (connectionMonitor) {
         this.openConnectionNonTransactionalChannels.get(connection).clear();
         this.openConnectionTransactionalChannels.get(connection).clear();
         connection.notifyCloseIfNecessary();
         ChannelCachingConnectionProxy newConnection =
             (ChannelCachingConnectionProxy) createConnection();
         /*
          * Applications already have a reference to the proxy, so we steal the new (or idle) connection's
          * target and remove the connection from the open list.
          */
         connection.target = newConnection.target;
         connection.closeNotified.set(false);
         this.openConnections.remove(newConnection);
       }
     }
     return doCreateBareChannel(connection, transactional);
   }
   return null;
 }
 private Channel doCreateBareChannel(
     ChannelCachingConnectionProxy connection, boolean transactional) {
   Channel channel = connection.createBareChannel(transactional);
   if (this.publisherConfirms) {
     try {
       channel.confirmSelect();
     } catch (IOException e) {
       logger.error("Could not configure the channel to receive publisher confirms", e);
     }
   }
   if (this.publisherConfirms || this.publisherReturns) {
     if (!(channel instanceof PublisherCallbackChannelImpl)) {
       channel = new PublisherCallbackChannelImpl(channel);
     }
   }
   if (channel != null) {
     channel.addShutdownListener(this);
   }
   return channel;
 }
 private Channel getChannel(ChannelCachingConnectionProxy connection, boolean transactional) {
   if (this.channelCheckoutTimeout > 0) {
     Semaphore checkoutPermits = this.checkoutPermits.get(connection);
     if (checkoutPermits != null) {
       try {
         if (!checkoutPermits.tryAcquire(this.channelCheckoutTimeout, TimeUnit.MILLISECONDS)) {
           throw new AmqpTimeoutException("No available channels");
         }
       } catch (InterruptedException e) {
         Thread.currentThread().interrupt();
         throw new AmqpTimeoutException("Interrupted while acquiring a channel", e);
       }
     }
   }
   LinkedList<ChannelProxy> channelList;
   if (this.cacheMode == CacheMode.CHANNEL) {
     channelList =
         transactional ? this.cachedChannelsTransactional : this.cachedChannelsNonTransactional;
   } else {
     channelList =
         transactional
             ? this.openConnectionTransactionalChannels.get(connection)
             : this.openConnectionNonTransactionalChannels.get(connection);
   }
   if (channelList == null) {
     channelList = new LinkedList<ChannelProxy>();
     if (transactional) {
       this.openConnectionTransactionalChannels.put(connection, channelList);
     } else {
       this.openConnectionNonTransactionalChannels.put(connection, channelList);
     }
   }
   ChannelProxy channel = null;
   if (connection.isOpen()) {
     synchronized (channelList) {
       while (!channelList.isEmpty()) {
         channel = channelList.removeFirst();
         if (logger.isTraceEnabled()) {
           logger.trace(channel + " retrieved from cache");
         }
         if (channel.isOpen()) {
           break;
         } else {
           try {
             Channel target = channel.getTargetChannel();
             if (target != null) {
               target.close(); // to remove it from auto-recovery if so configured
             }
           } catch (AlreadyClosedException e) {
             if (logger.isTraceEnabled()) {
               logger.trace(channel + " is already closed");
             }
           } catch (IOException e) {
             if (logger.isDebugEnabled()) {
               logger.debug("Unexpected Exception closing channel " + e.getMessage());
             }
           } catch (TimeoutException e) {
             if (logger.isWarnEnabled()) {
               logger.warn("TimeoutException closing channel " + e.getMessage());
             }
           }
           channel = null;
         }
       }
     }
     if (channel != null) {
       if (logger.isTraceEnabled()) {
         logger.trace("Found cached Rabbit Channel: " + channel.toString());
       }
     }
   }
   if (channel == null) {
     channel = getCachedChannelProxy(connection, channelList, transactional);
   }
   return channel;
 }