541 lines
23 KiB
Java
541 lines
23 KiB
Java
package com.google.common.util.concurrent;
|
|
|
|
import com.google.common.base.Function;
|
|
import com.google.common.base.MoreObjects;
|
|
import com.google.common.base.Preconditions;
|
|
import com.google.common.base.Predicates;
|
|
import com.google.common.base.Stopwatch;
|
|
import com.google.common.collect.Collections2;
|
|
import com.google.common.collect.ImmutableCollection;
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.collect.ImmutableSet;
|
|
import com.google.common.collect.ImmutableSetMultimap;
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Maps;
|
|
import com.google.common.collect.MultimapBuilder;
|
|
import com.google.common.collect.Multimaps;
|
|
import com.google.common.collect.Multiset;
|
|
import com.google.common.collect.Ordering;
|
|
import com.google.common.collect.SetMultimap;
|
|
import com.google.common.collect.UnmodifiableIterator;
|
|
import com.google.common.util.concurrent.ListenerCallQueue;
|
|
import com.google.common.util.concurrent.Monitor;
|
|
import com.google.common.util.concurrent.Service;
|
|
import java.lang.ref.WeakReference;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.EnumSet;
|
|
import java.util.Map;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeoutException;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
/* loaded from: classes2.dex */
|
|
public final class ServiceManager implements ServiceManagerBridge {
|
|
private final ImmutableList<Service> services;
|
|
private final ServiceManagerState state;
|
|
private static final Logger logger = Logger.getLogger(ServiceManager.class.getName());
|
|
private static final ListenerCallQueue.Event<Listener> HEALTHY_EVENT = new ListenerCallQueue.Event<Listener>() { // from class: com.google.common.util.concurrent.ServiceManager.1
|
|
@Override // com.google.common.util.concurrent.ListenerCallQueue.Event
|
|
public void call(Listener listener) {
|
|
listener.healthy();
|
|
}
|
|
|
|
public String toString() {
|
|
return "healthy()";
|
|
}
|
|
};
|
|
private static final ListenerCallQueue.Event<Listener> STOPPED_EVENT = new ListenerCallQueue.Event<Listener>() { // from class: com.google.common.util.concurrent.ServiceManager.2
|
|
@Override // com.google.common.util.concurrent.ListenerCallQueue.Event
|
|
public void call(Listener listener) {
|
|
listener.stopped();
|
|
}
|
|
|
|
public String toString() {
|
|
return "stopped()";
|
|
}
|
|
};
|
|
|
|
/* loaded from: classes2.dex */
|
|
public static abstract class Listener {
|
|
public void failure(Service service) {
|
|
}
|
|
|
|
public void healthy() {
|
|
}
|
|
|
|
public void stopped() {
|
|
}
|
|
}
|
|
|
|
public ServiceManager(Iterable<? extends Service> iterable) {
|
|
ImmutableList<Service> copyOf = ImmutableList.copyOf(iterable);
|
|
if (copyOf.isEmpty()) {
|
|
logger.log(Level.WARNING, "ServiceManager configured with no services. Is your application configured properly?", (Throwable) new EmptyServiceManagerWarning());
|
|
copyOf = ImmutableList.of(new NoOpService());
|
|
}
|
|
ServiceManagerState serviceManagerState = new ServiceManagerState(copyOf);
|
|
this.state = serviceManagerState;
|
|
this.services = copyOf;
|
|
WeakReference weakReference = new WeakReference(serviceManagerState);
|
|
UnmodifiableIterator<Service> it = copyOf.iterator();
|
|
while (it.hasNext()) {
|
|
Service next = it.next();
|
|
next.addListener(new ServiceListener(next, weakReference), MoreExecutors.directExecutor());
|
|
Preconditions.checkArgument(next.state() == Service.State.NEW, "Can only manage NEW services, %s", next);
|
|
}
|
|
this.state.markReady();
|
|
}
|
|
|
|
public final void addListener(Listener listener, Executor executor) {
|
|
this.state.addListener(listener, executor);
|
|
}
|
|
|
|
public final ServiceManager startAsync() {
|
|
UnmodifiableIterator<Service> it = this.services.iterator();
|
|
while (it.hasNext()) {
|
|
Service next = it.next();
|
|
Service.State state = next.state();
|
|
Preconditions.checkState(state == Service.State.NEW, "Service %s is %s, cannot start it.", next, state);
|
|
}
|
|
UnmodifiableIterator<Service> it2 = this.services.iterator();
|
|
while (it2.hasNext()) {
|
|
Service next2 = it2.next();
|
|
try {
|
|
this.state.tryStartTiming(next2);
|
|
next2.startAsync();
|
|
} catch (IllegalStateException e) {
|
|
Logger logger2 = logger;
|
|
Level level = Level.WARNING;
|
|
String valueOf = String.valueOf(next2);
|
|
StringBuilder sb = new StringBuilder(String.valueOf(valueOf).length() + 24);
|
|
sb.append("Unable to start Service ");
|
|
sb.append(valueOf);
|
|
logger2.log(level, sb.toString(), (Throwable) e);
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public final void awaitHealthy() {
|
|
this.state.awaitHealthy();
|
|
}
|
|
|
|
public final void awaitHealthy(long j, TimeUnit timeUnit) throws TimeoutException {
|
|
this.state.awaitHealthy(j, timeUnit);
|
|
}
|
|
|
|
public final ServiceManager stopAsync() {
|
|
UnmodifiableIterator<Service> it = this.services.iterator();
|
|
while (it.hasNext()) {
|
|
it.next().stopAsync();
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public final void awaitStopped() {
|
|
this.state.awaitStopped();
|
|
}
|
|
|
|
public final void awaitStopped(long j, TimeUnit timeUnit) throws TimeoutException {
|
|
this.state.awaitStopped(j, timeUnit);
|
|
}
|
|
|
|
public final boolean isHealthy() {
|
|
UnmodifiableIterator<Service> it = this.services.iterator();
|
|
while (it.hasNext()) {
|
|
if (!it.next().isRunning()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.ServiceManagerBridge
|
|
public final ImmutableSetMultimap<Service.State, Service> servicesByState() {
|
|
return this.state.servicesByState();
|
|
}
|
|
|
|
public final ImmutableMap<Service, Long> startupTimes() {
|
|
return this.state.startupTimes();
|
|
}
|
|
|
|
public final String toString() {
|
|
return MoreObjects.toStringHelper((Class<?>) ServiceManager.class).add("services", Collections2.filter(this.services, Predicates.not(Predicates.instanceOf(NoOpService.class)))).toString();
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: package-private */
|
|
/* loaded from: classes2.dex */
|
|
public static final class ServiceManagerState {
|
|
final Monitor.Guard awaitHealthGuard;
|
|
final ListenerCallQueue<Listener> listeners;
|
|
final Monitor monitor = new Monitor();
|
|
final int numberOfServices;
|
|
boolean ready;
|
|
final SetMultimap<Service.State, Service> servicesByState;
|
|
final Map<Service, Stopwatch> startupTimers;
|
|
final Multiset<Service.State> states;
|
|
final Monitor.Guard stoppedGuard;
|
|
boolean transitioned;
|
|
|
|
/* loaded from: classes2.dex */
|
|
final class AwaitHealthGuard extends Monitor.Guard {
|
|
final ServiceManagerState this$0;
|
|
|
|
/* JADX WARN: 'super' call moved to the top of the method (can break code semantics) */
|
|
AwaitHealthGuard(ServiceManagerState serviceManagerState) {
|
|
super(serviceManagerState.monitor);
|
|
this.this$0 = serviceManagerState;
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.Monitor.Guard
|
|
public final boolean isSatisfied() {
|
|
return this.this$0.states.count(Service.State.RUNNING) == this.this$0.numberOfServices || this.this$0.states.contains(Service.State.STOPPING) || this.this$0.states.contains(Service.State.TERMINATED) || this.this$0.states.contains(Service.State.FAILED);
|
|
}
|
|
}
|
|
|
|
/* loaded from: classes2.dex */
|
|
final class StoppedGuard extends Monitor.Guard {
|
|
final ServiceManagerState this$0;
|
|
|
|
/* JADX WARN: 'super' call moved to the top of the method (can break code semantics) */
|
|
StoppedGuard(ServiceManagerState serviceManagerState) {
|
|
super(serviceManagerState.monitor);
|
|
this.this$0 = serviceManagerState;
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.Monitor.Guard
|
|
public final boolean isSatisfied() {
|
|
return this.this$0.states.count(Service.State.TERMINATED) + this.this$0.states.count(Service.State.FAILED) == this.this$0.numberOfServices;
|
|
}
|
|
}
|
|
|
|
ServiceManagerState(ImmutableCollection<Service> immutableCollection) {
|
|
SetMultimap<Service.State, Service> build = MultimapBuilder.enumKeys(Service.State.class).linkedHashSetValues().build();
|
|
this.servicesByState = build;
|
|
this.states = build.keys();
|
|
this.startupTimers = Maps.newIdentityHashMap();
|
|
this.awaitHealthGuard = new AwaitHealthGuard(this);
|
|
this.stoppedGuard = new StoppedGuard(this);
|
|
this.listeners = new ListenerCallQueue<>();
|
|
this.numberOfServices = immutableCollection.size();
|
|
build.putAll(Service.State.NEW, immutableCollection);
|
|
}
|
|
|
|
final void tryStartTiming(Service service) {
|
|
this.monitor.enter();
|
|
try {
|
|
if (this.startupTimers.get(service) == null) {
|
|
this.startupTimers.put(service, Stopwatch.createStarted());
|
|
}
|
|
} finally {
|
|
this.monitor.leave();
|
|
}
|
|
}
|
|
|
|
final void markReady() {
|
|
this.monitor.enter();
|
|
try {
|
|
if (!this.transitioned) {
|
|
this.ready = true;
|
|
return;
|
|
}
|
|
ArrayList newArrayList = Lists.newArrayList();
|
|
UnmodifiableIterator<Service> it = servicesByState().values().iterator();
|
|
while (it.hasNext()) {
|
|
Service next = it.next();
|
|
if (next.state() != Service.State.NEW) {
|
|
newArrayList.add(next);
|
|
}
|
|
}
|
|
String valueOf = String.valueOf(newArrayList);
|
|
StringBuilder sb = new StringBuilder(String.valueOf(valueOf).length() + 89);
|
|
sb.append("Services started transitioning asynchronously before the ServiceManager was constructed: ");
|
|
sb.append(valueOf);
|
|
throw new IllegalArgumentException(sb.toString());
|
|
} finally {
|
|
this.monitor.leave();
|
|
}
|
|
}
|
|
|
|
final void addListener(Listener listener, Executor executor) {
|
|
this.listeners.addListener(listener, executor);
|
|
}
|
|
|
|
final void awaitHealthy() {
|
|
this.monitor.enterWhenUninterruptibly(this.awaitHealthGuard);
|
|
try {
|
|
checkHealthy();
|
|
} finally {
|
|
this.monitor.leave();
|
|
}
|
|
}
|
|
|
|
final void awaitHealthy(long j, TimeUnit timeUnit) throws TimeoutException {
|
|
this.monitor.enter();
|
|
try {
|
|
if (!this.monitor.waitForUninterruptibly(this.awaitHealthGuard, j, timeUnit)) {
|
|
String valueOf = String.valueOf(Multimaps.filterKeys((SetMultimap) this.servicesByState, Predicates.in(ImmutableSet.of(Service.State.NEW, Service.State.STARTING))));
|
|
StringBuilder sb = new StringBuilder(String.valueOf(valueOf).length() + 93);
|
|
sb.append("Timeout waiting for the services to become healthy. The following services have not started: ");
|
|
sb.append(valueOf);
|
|
throw new TimeoutException(sb.toString());
|
|
}
|
|
checkHealthy();
|
|
} finally {
|
|
this.monitor.leave();
|
|
}
|
|
}
|
|
|
|
final void awaitStopped() {
|
|
this.monitor.enterWhenUninterruptibly(this.stoppedGuard);
|
|
this.monitor.leave();
|
|
}
|
|
|
|
final void awaitStopped(long j, TimeUnit timeUnit) throws TimeoutException {
|
|
this.monitor.enter();
|
|
try {
|
|
if (this.monitor.waitForUninterruptibly(this.stoppedGuard, j, timeUnit)) {
|
|
return;
|
|
}
|
|
String valueOf = String.valueOf(Multimaps.filterKeys((SetMultimap) this.servicesByState, Predicates.not(Predicates.in(EnumSet.of(Service.State.TERMINATED, Service.State.FAILED)))));
|
|
StringBuilder sb = new StringBuilder(String.valueOf(valueOf).length() + 83);
|
|
sb.append("Timeout waiting for the services to stop. The following services have not stopped: ");
|
|
sb.append(valueOf);
|
|
throw new TimeoutException(sb.toString());
|
|
} finally {
|
|
this.monitor.leave();
|
|
}
|
|
}
|
|
|
|
final ImmutableSetMultimap<Service.State, Service> servicesByState() {
|
|
ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder();
|
|
this.monitor.enter();
|
|
try {
|
|
for (Map.Entry<Service.State, Service> entry : this.servicesByState.entries()) {
|
|
if (!(entry.getValue() instanceof NoOpService)) {
|
|
builder.put((Map.Entry) entry);
|
|
}
|
|
}
|
|
this.monitor.leave();
|
|
return builder.build();
|
|
} catch (Throwable th) {
|
|
this.monitor.leave();
|
|
throw th;
|
|
}
|
|
}
|
|
|
|
final ImmutableMap<Service, Long> startupTimes() {
|
|
this.monitor.enter();
|
|
try {
|
|
ArrayList newArrayListWithCapacity = Lists.newArrayListWithCapacity(this.startupTimers.size());
|
|
for (Map.Entry<Service, Stopwatch> entry : this.startupTimers.entrySet()) {
|
|
Service key = entry.getKey();
|
|
Stopwatch value = entry.getValue();
|
|
if (!value.isRunning() && !(key instanceof NoOpService)) {
|
|
newArrayListWithCapacity.add(Maps.immutableEntry(key, Long.valueOf(value.elapsed(TimeUnit.MILLISECONDS))));
|
|
}
|
|
}
|
|
this.monitor.leave();
|
|
Collections.sort(newArrayListWithCapacity, Ordering.natural().onResultOf(new Function<Map.Entry<Service, Long>, Long>(this) { // from class: com.google.common.util.concurrent.ServiceManager.ServiceManagerState.1
|
|
@Override // com.google.common.base.Function
|
|
public Long apply(Map.Entry<Service, Long> entry2) {
|
|
return entry2.getValue();
|
|
}
|
|
}));
|
|
return ImmutableMap.copyOf(newArrayListWithCapacity);
|
|
} catch (Throwable th) {
|
|
this.monitor.leave();
|
|
throw th;
|
|
}
|
|
}
|
|
|
|
final void transitionService(Service service, Service.State state, Service.State state2) {
|
|
Monitor monitor;
|
|
Preconditions.checkNotNull(service);
|
|
Preconditions.checkArgument(state != state2);
|
|
this.monitor.enter();
|
|
try {
|
|
this.transitioned = true;
|
|
if (this.ready) {
|
|
Preconditions.checkState(this.servicesByState.remove(state, service), "Service %s not at the expected location in the state map %s", service, state);
|
|
Preconditions.checkState(this.servicesByState.put(state2, service), "Service %s in the state map unexpectedly at %s", service, state2);
|
|
Stopwatch stopwatch = this.startupTimers.get(service);
|
|
if (stopwatch == null) {
|
|
stopwatch = Stopwatch.createStarted();
|
|
this.startupTimers.put(service, stopwatch);
|
|
}
|
|
if (state2.compareTo(Service.State.RUNNING) >= 0 && stopwatch.isRunning()) {
|
|
stopwatch.stop();
|
|
if (!(service instanceof NoOpService)) {
|
|
ServiceManager.logger.log(Level.FINE, "Started {0} in {1}.", new Object[]{service, stopwatch});
|
|
}
|
|
}
|
|
if (state2 == Service.State.FAILED) {
|
|
enqueueFailedEvent(service);
|
|
}
|
|
if (this.states.count(Service.State.RUNNING) == this.numberOfServices) {
|
|
enqueueHealthyEvent();
|
|
} else if (this.states.count(Service.State.TERMINATED) + this.states.count(Service.State.FAILED) == this.numberOfServices) {
|
|
enqueueStoppedEvent();
|
|
}
|
|
monitor = this.monitor;
|
|
} else {
|
|
monitor = this.monitor;
|
|
}
|
|
monitor.leave();
|
|
dispatchListenerEvents();
|
|
} catch (Throwable th) {
|
|
this.monitor.leave();
|
|
dispatchListenerEvents();
|
|
throw th;
|
|
}
|
|
}
|
|
|
|
final void enqueueStoppedEvent() {
|
|
this.listeners.enqueue(ServiceManager.STOPPED_EVENT);
|
|
}
|
|
|
|
final void enqueueHealthyEvent() {
|
|
this.listeners.enqueue(ServiceManager.HEALTHY_EVENT);
|
|
}
|
|
|
|
final void enqueueFailedEvent(Service service) {
|
|
this.listeners.enqueue(new ListenerCallQueue.Event<Listener>(this, service) { // from class: com.google.common.util.concurrent.ServiceManager.ServiceManagerState.2
|
|
final Service val$service;
|
|
|
|
{
|
|
this.val$service = service;
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.ListenerCallQueue.Event
|
|
public void call(Listener listener) {
|
|
listener.failure(this.val$service);
|
|
}
|
|
|
|
public String toString() {
|
|
String valueOf = String.valueOf(this.val$service);
|
|
StringBuilder sb = new StringBuilder(String.valueOf(valueOf).length() + 18);
|
|
sb.append("failed({service=");
|
|
sb.append(valueOf);
|
|
sb.append("})");
|
|
return sb.toString();
|
|
}
|
|
});
|
|
}
|
|
|
|
final void dispatchListenerEvents() {
|
|
Preconditions.checkState(!this.monitor.isOccupiedByCurrentThread(), "It is incorrect to execute listeners with the monitor held.");
|
|
this.listeners.dispatch();
|
|
}
|
|
|
|
final void checkHealthy() {
|
|
if (this.states.count(Service.State.RUNNING) == this.numberOfServices) {
|
|
return;
|
|
}
|
|
String valueOf = String.valueOf(Multimaps.filterKeys((SetMultimap) this.servicesByState, Predicates.not(Predicates.equalTo(Service.State.RUNNING))));
|
|
StringBuilder sb = new StringBuilder(String.valueOf(valueOf).length() + 79);
|
|
sb.append("Expected to be healthy after starting. The following services are not running: ");
|
|
sb.append(valueOf);
|
|
throw new IllegalStateException(sb.toString());
|
|
}
|
|
}
|
|
|
|
/* loaded from: classes2.dex */
|
|
static final class ServiceListener extends Service.Listener {
|
|
final Service service;
|
|
final WeakReference<ServiceManagerState> state;
|
|
|
|
ServiceListener(Service service, WeakReference<ServiceManagerState> weakReference) {
|
|
this.service = service;
|
|
this.state = weakReference;
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.Service.Listener
|
|
public final void starting() {
|
|
ServiceManagerState serviceManagerState = this.state.get();
|
|
if (serviceManagerState != null) {
|
|
serviceManagerState.transitionService(this.service, Service.State.NEW, Service.State.STARTING);
|
|
if (this.service instanceof NoOpService) {
|
|
return;
|
|
}
|
|
ServiceManager.logger.log(Level.FINE, "Starting {0}.", this.service);
|
|
}
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.Service.Listener
|
|
public final void running() {
|
|
ServiceManagerState serviceManagerState = this.state.get();
|
|
if (serviceManagerState != null) {
|
|
serviceManagerState.transitionService(this.service, Service.State.STARTING, Service.State.RUNNING);
|
|
}
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.Service.Listener
|
|
public final void stopping(Service.State state) {
|
|
ServiceManagerState serviceManagerState = this.state.get();
|
|
if (serviceManagerState != null) {
|
|
serviceManagerState.transitionService(this.service, state, Service.State.STOPPING);
|
|
}
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.Service.Listener
|
|
public final void terminated(Service.State state) {
|
|
ServiceManagerState serviceManagerState = this.state.get();
|
|
if (serviceManagerState != null) {
|
|
if (!(this.service instanceof NoOpService)) {
|
|
ServiceManager.logger.log(Level.FINE, "Service {0} has terminated. Previous state was: {1}", new Object[]{this.service, state});
|
|
}
|
|
serviceManagerState.transitionService(this.service, state, Service.State.TERMINATED);
|
|
}
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.Service.Listener
|
|
public final void failed(Service.State state, Throwable th) {
|
|
ServiceManagerState serviceManagerState = this.state.get();
|
|
if (serviceManagerState != null) {
|
|
if (!(this.service instanceof NoOpService)) {
|
|
Logger logger = ServiceManager.logger;
|
|
Level level = Level.SEVERE;
|
|
String valueOf = String.valueOf(this.service);
|
|
String valueOf2 = String.valueOf(state);
|
|
StringBuilder sb = new StringBuilder(String.valueOf(valueOf).length() + 34 + String.valueOf(valueOf2).length());
|
|
sb.append("Service ");
|
|
sb.append(valueOf);
|
|
sb.append(" has failed in the ");
|
|
sb.append(valueOf2);
|
|
sb.append(" state.");
|
|
logger.log(level, sb.toString(), th);
|
|
}
|
|
serviceManagerState.transitionService(this.service, state, Service.State.FAILED);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: package-private */
|
|
/* loaded from: classes2.dex */
|
|
public static final class NoOpService extends AbstractService {
|
|
private NoOpService() {
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.AbstractService
|
|
protected final void doStart() {
|
|
notifyStarted();
|
|
}
|
|
|
|
@Override // com.google.common.util.concurrent.AbstractService
|
|
protected final void doStop() {
|
|
notifyStopped();
|
|
}
|
|
}
|
|
|
|
/* loaded from: classes2.dex */
|
|
static final class EmptyServiceManagerWarning extends Throwable {
|
|
private EmptyServiceManagerWarning() {
|
|
}
|
|
}
|
|
}
|