/** * Initiates an orderly shutdown in which preexisting calls continue but new calls are immediately * cancelled. */ public ChannelImpl shutdown() { ClientTransport savedActiveTransport; synchronized (lock) { if (shutdown) { return this; } shutdown = true; // After shutdown there are no new calls, so no new cancellation tasks are needed scheduledExecutor = SharedResourceHolder.release(TIMER_SERVICE, scheduledExecutor); savedActiveTransport = activeTransport; if (savedActiveTransport != null) { activeTransport = null; } else if (transports.isEmpty()) { terminated = true; lock.notifyAll(); if (terminationRunnable != null) { terminationRunnable.run(); } } } if (savedActiveTransport != null) { savedActiveTransport.shutdown(); } return this; }
private ClientTransport obtainActiveTransport() { ClientTransport savedActiveTransport = activeTransport; // If we know there is an active transport and we are not in backoff mode, return quickly. if (savedActiveTransport != null && !(savedActiveTransport instanceof InactiveTransport)) { return savedActiveTransport; } synchronized (lock) { if (shutdown) { return null; } savedActiveTransport = activeTransport; if (savedActiveTransport instanceof InactiveTransport) { if (System.nanoTime() > TimeUnit.MILLISECONDS.toNanos(reconnectTimeMillis)) { // The timeout expired, clear the inactive transport and update the shutdown status to // something that is retryable. activeTransport = null; savedActiveTransport = activeTransport; } else { // We are still in backoff mode, just return the inactive transport. return savedActiveTransport; } } if (savedActiveTransport != null) { return savedActiveTransport; } // There is no active transport, or we just finished backoff. Create a new transport. ClientTransport newActiveTransport = transportFactory.newClientTransport(); transports.add(newActiveTransport); boolean failed = true; try { newActiveTransport.start(new TransportListener(newActiveTransport)); failed = false; } finally { if (failed) { transports.remove(newActiveTransport); } } // It's possible that start() called transportShutdown() and transportTerminated(). If so, we // wouldn't want to make it the active transport. if (transports.contains(newActiveTransport)) { // start() must return before we set activeTransport, since activeTransport is accessed // without a lock. activeTransport = newActiveTransport; } return newActiveTransport; } }