package cloudone.internal; import cloudone.LifecycleService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch; /** * @author Martin Mares (martin.mares at oracle.com) */ public class LifecycleServiceImpl implements LifecycleService { private enum Status { IDLE, RUNNING, STOPPING; } private static final LifecycleServiceImpl INSTANCE = new LifecycleServiceImpl(); private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleServiceImpl.class); private volatile Status status = Status.IDLE; private volatile CountDownLatch latch; private volatile List<LifecycleListener> lifecycleListeners = Collections.synchronizedList(new ArrayList<>()); private boolean hooked = false; private void fireStarted() { for (LifecycleListener lifecycleListener : lifecycleListeners) { try { lifecycleListener.onStart(); } catch (Exception exc) { LOGGER.warn("Exception from one of lifecycleListeners.", exc); } } } private void fireShutdown() { for (LifecycleListener lifecycleListener : lifecycleListeners) { try { lifecycleListener.onShutdown(); } catch (Exception exc) { LOGGER.warn("Exception from one of lifecycleListeners.", exc); } } } public synchronized void start() { switch (status) { case IDLE: latch = new CountDownLatch(1); setStatus(Status.RUNNING); if (!hooked) { Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { if (status == Status.RUNNING) { shutdown(); } } }); } fireStarted(); break; case STOPPING: throw new RuntimeException("Server is yet in shutdown mode. Can not start"); case RUNNING: return; } } @Override public synchronized void shutdown() { if (status == Status.RUNNING) { setStatus(Status.STOPPING); fireShutdown(); if (latch != null) { latch.countDown(); } setStatus(Status.IDLE); } } @Override public void registerListener(LifecycleListener listener) { lifecycleListeners.add(listener); } public void awaitForShutdown() throws InterruptedException { if (status == Status.RUNNING && latch != null) { latch.await(); } } public Status getStatus() { return status; } private synchronized void setStatus(Status status) { if (this.status != status) { this.status = status; LOGGER.info("*** Server is " + status); } } public static LifecycleServiceImpl getInstance() { return INSTANCE; } }