package org.jboss.as.server;

import org.jboss.as.server.logging.ServerLogger;
import org.jboss.as.server.suspend.OperationListener;
import org.jboss.as.server.suspend.SuspendController;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;


/**
 * A service that allows the server to wait until graceful shutdown is complete.
 *
 * This is mainly used to perform graceful shutdown in domain mode, to delay the System.exit() call
 * until the server has suspended.
 *
 * @author Stuart Douglas
 */
public class GracefulShutdownService implements Service<GracefulShutdownService> {

    public static final ServiceName SERVICE_NAME = ServiceName.JBOSS.append("server", "graceful-shutdown-service");

    private final InjectedValue<SuspendController> suspendControllerInjectedValue = new InjectedValue<>();

    private boolean suspend = false;
    private boolean shuttingDown = false;
    private final Object lock = new Object();

    private final OperationListener listener = new OperationListener() {
        @Override
        public void suspendStarted() {
            synchronized (lock) {
                suspend = true;
            }
        }

        @Override
        public void complete() {
            synchronized (lock) {
                suspend = false;
                lock.notifyAll();
            }
        }

        @Override
        public void cancelled() {

            synchronized (lock) {
                suspend = false;
                lock.notifyAll();
            }
        }

        @Override
        public void timeout() {
            synchronized (lock) {
                suspend = false;
                lock.notifyAll();
            }
        }
    };

    @Override
    public void start(StartContext context) throws StartException {
        suspendControllerInjectedValue.getValue().addListener(listener);
    }

    @Override
    public void stop(StopContext context) {
        suspendControllerInjectedValue.getValue().removeListener(listener);
    }

    public void startGracefulShutdown() {
        synchronized (lock) {
            shuttingDown = true;
        }
    }

    public void awaitSuspend() {
        synchronized (lock) {
            while (suspend && shuttingDown) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    ServerLogger.AS_ROOT_LOGGER.debug("Exception waiting for graceful shutdown", e);
                }
            }
        }
    }

    public InjectedValue<SuspendController> getSuspendControllerInjectedValue() {
        return suspendControllerInjectedValue;
    }

    @Override
    public GracefulShutdownService getValue() throws IllegalStateException, IllegalArgumentException {
        return this;
    }
}
