package org.erlide.runtime.service; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.erlide.util.services.Provider; import com.google.common.collect.Maps; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.Service; public class RestartableService implements Service { private Service delegate; private final ServiceRestartPolicy policy; private final Provider<Service> factory; private final Map<Listener, Executor> listeners; public RestartableService(final Provider<Service> factory, final ServiceRestartPolicy policy) { this.factory = factory; this.policy = policy; listeners = Maps.newHashMap(); } private final class RestartListener extends Listener { @Override public void failed(final State from, final Throwable failure) { if (policy.shouldRestart()) { startAsync(); } else { for (final Entry<Listener, Executor> l : listeners.entrySet()) { l.getKey().failed(from, failure); } } } @Override public void starting() { for (final Entry<Listener, Executor> l : listeners.entrySet()) { l.getKey().starting(); } } @Override public void running() { for (final Entry<Listener, Executor> l : listeners.entrySet()) { l.getKey().running(); } } @Override public void stopping(final Service.State from) { for (final Entry<Listener, Executor> l : listeners.entrySet()) { l.getKey().stopping(from); } } @Override public void terminated(final State from) { for (final Entry<Listener, Executor> l : listeners.entrySet()) { l.getKey().terminated(from); } } } /** * Used for testing only. * * @return delegate */ public Service getDelegate() { return delegate; } @Override public Service startAsync() { delegate = factory.get(); delegate.addListener(new RestartListener(), MoreExecutors.sameThreadExecutor()); delegate.startAsync(); policy.notifyRestart(); return this; } @Override public boolean isRunning() { return delegate.isRunning(); } @Override public State state() { return delegate.state(); } @Override public Service stopAsync() { delegate.stopAsync(); return this; } @Override public void awaitRunning() { delegate.awaitRunning(); } @Override public void awaitRunning(final long timeout, final TimeUnit unit) throws TimeoutException { delegate.awaitRunning(timeout, unit); } @Override public void awaitTerminated() { delegate.awaitTerminated(); } @Override public void awaitTerminated(final long timeout, final TimeUnit unit) throws TimeoutException { delegate.awaitTerminated(timeout, unit); } @Override public Throwable failureCause() { return delegate.failureCause(); } @Override public void addListener(final Listener listener, final Executor executor) { synchronized (listeners) { listeners.put(listener, executor); } } }