@Test public void connectIsLazy() { SocketAddress addr = mock(SocketAddress.class); createInternalSubchannel(addr); int transportsCreated = 0; verify(mockTransportFactory, times(transportsCreated)) .newClientTransport(addr, createClientTransportOptions()); internalSubchannel.obtainActiveTransport(); assertExactCallbackInvokes("onStateChange:CONNECTING"); verify(mockTransportFactory, times(++transportsCreated)) .newClientTransport(addr, createClientTransportOptions()); transports.poll().listener.transportShutdown(Status.UNAVAILABLE); assertExactCallbackInvokes("onStateChange:" + UNAVAILABLE_STATE); fakeClock.forwardNanos(10); assertExactCallbackInvokes("onStateChange:CONNECTING"); verify(mockTransportFactory, times(++transportsCreated)) .newClientTransport(addr, createClientTransportOptions()); transports.peek().listener.transportReady(); assertExactCallbackInvokes("onStateChange:READY"); transports.poll().listener.transportShutdown(Status.UNAVAILABLE); assertExactCallbackInvokes("onStateChange:IDLE"); assertEquals(0, fakeClock.numPendingTasks()); assertEquals(0, fakeExecutor.numPendingTasks()); internalSubchannel.obtainActiveTransport(); assertExactCallbackInvokes("onStateChange:CONNECTING"); verify(mockTransportFactory, times(++transportsCreated)) .newClientTransport(addr, createClientTransportOptions()); }
@Nullable ClientTransport obtainActiveTransport() { ClientTransport savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } try { synchronized (lock) { savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } if (state.getState() == IDLE) { channelLogger.log(ChannelLogLevel.INFO, "CONNECTING as requested"); gotoNonErrorState(CONNECTING); startNewTransport(); } } } finally { syncContext.drain(); } return null; }
InternalSubchannel implements InternalInstrumented<ChannelStats> { @Nullable ClientTransport obtainActiveTransport() { ClientTransport savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } try { synchronized (lock) { savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } if (state.getState() == IDLE) { channelLogger.log(ChannelLogLevel.INFO, "CONNECTING as requested"); gotoNonErrorState(CONNECTING); startNewTransport(); } } } finally { syncContext.drain(); } return null; } }
InternalSubchannel implements InternalInstrumented<ChannelStats> { @Nullable ClientTransport obtainActiveTransport() { ClientTransport savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } try { synchronized (lock) { savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } if (state.getState() == IDLE) { channelLogger.log(ChannelLogLevel.INFO, "CONNECTING as requested"); gotoNonErrorState(CONNECTING); startNewTransport(); } } } finally { syncContext.drain(); } return null; } InternalSubchannel(List<EquivalentAddressGroup> addressGroups, String authority, String userAgent,
      BackoffPolicy.Provider backoffPolicyProvider,
      ClientTransportFactory transportFactory, ScheduledExecutorService scheduledExecutor,
      Supplier<Stopwatch> stopwatchSupplier, SynchronizationContext syncContext, Callback callback,
      InternalChannelz channelz, CallTracer callsTracer, ChannelTracer channelTracer,
      InternalLogId logId, TimeProvider timeProvider); }
InternalSubchannel implements InternalInstrumented<ChannelStats> { @Nullable ClientTransport obtainActiveTransport() { ClientTransport savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } try { synchronized (lock) { savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } if (state.getState() == IDLE) { channelLogger.log(ChannelLogLevel.INFO, "CONNECTING as requested"); gotoNonErrorState(CONNECTING); startNewTransport(); } } } finally { syncContext.drain(); } return null; } InternalSubchannel(List<EquivalentAddressGroup> addressGroups, String authority, String userAgent,
      BackoffPolicy.Provider backoffPolicyProvider,
      ClientTransportFactory transportFactory, ScheduledExecutorService scheduledExecutor,
      Supplier<Stopwatch> stopwatchSupplier, SynchronizationContext syncContext, Callback callback,
      InternalChannelz channelz, CallTracer callsTracer, ChannelTracer channelTracer,
      InternalLogId logId, TimeProvider timeProvider); void updateAddresses(List<EquivalentAddressGroup> newAddressGroups); void shutdown(Status reason); @Override String toString(); @Override InternalLogId getLogId(); @Override ListenableFuture<ChannelStats> getStats(); }
InternalSubchannel implements InternalInstrumented<ChannelStats> { @Nullable ClientTransport obtainActiveTransport() { ClientTransport savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } try { synchronized (lock) { savedTransport = activeTransport; if (savedTransport != null) { return savedTransport; } if (state.getState() == IDLE) { channelLogger.log(ChannelLogLevel.INFO, "CONNECTING as requested"); gotoNonErrorState(CONNECTING); startNewTransport(); } } } finally { syncContext.drain(); } return null; } InternalSubchannel(List<EquivalentAddressGroup> addressGroups, String authority, String userAgent,
      BackoffPolicy.Provider backoffPolicyProvider,
      ClientTransportFactory transportFactory, ScheduledExecutorService scheduledExecutor,
      Supplier<Stopwatch> stopwatchSupplier, SynchronizationContext syncContext, Callback callback,
      InternalChannelz channelz, CallTracer callsTracer, ChannelTracer channelTracer,
      InternalLogId logId, TimeProvider timeProvider); void updateAddresses(List<EquivalentAddressGroup> newAddressGroups); void shutdown(Status reason); @Override String toString(); @Override InternalLogId getLogId(); @Override ListenableFuture<ChannelStats> getStats();  }