/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2010, Red Hat, Inc., and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.jboss.msc.service;

import org.jboss.msc.value.Value;

/**
 * A controller for a single service instance.
 *
 * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
 */
public interface ServiceController<S> extends Value<S> {

    /**
     * Get the service container associated with this controller.
     *
     * @return the container
     */
    ServiceContainer getServiceContainer();

    /**
     * Get the service controller's current mode.
     *
     * @return the controller mode
     */
    Mode getMode();

    /**
     * Change the service controller's current mode.  Might result in the service starting or stopping.
     *
     * @param mode the new controller mode
     */
    void setMode(Mode mode);

    /**
     * Get the current service state.
     *
     * @return the current state
     */
    State getState();

    /**
     * Get the service.
     *
     * @return the service
     * @throws IllegalStateException if the service is not available
     */
    S getValue() throws IllegalStateException;

    /**
     * Get the name of this service, if any.
     *
     * @return the name, or {@code null} if none was specified.
     */
    ServiceName getName();

    /**
     * Add a service listener.  The method corresponding to the current service state is called.
     *
     * @param serviceListener the service listener
     */
    void addListener(ServiceListener<? super S> serviceListener);

    /**
     * Remove a service listener.
     *
     * @param serviceListener the service listener to remove
     */
    void removeListener(ServiceListener<? super S> serviceListener);

    /**
     * Remove this service from the controller.  Once removed, this service may no longer be started.
     *
     * @throws IllegalStateException if the service is not in the {@code DOWN} state
     */
    void remove() throws IllegalStateException;

    /**
     * Get the reason why the last start failed.
     *
     * @return the last start exception, or {@code null} if the last start succeeded or the service has not yet started
     */
    StartException getStartException();

    /**
     * Retry a failed service.  Does nothing if the state is not {@link State#START_FAILED}.
     */
    void retry();

    /**
     * A possible state for a service controller.
     */
    enum State {

        /**
         * Down.  All dependents are down.
         *
         * @enter all dependents are DOWN
         * @exit STARTING all dependencies are UP
         * @exit * running listener count = 0
         * @exit STARTING mode is IMMEDIATE or AUTOMATIC, or mode is ON_DEMAND and demand count > 0
         * @exit REMOVED no dependents exist
         */
        DOWN,
        /**
         * Service is starting.  Dependencies may not enter the {@code DOWN} state.  This state may not be left until
         * the {@code start} method has finished or failed.
         *
         * @enter all dependencies are UP
         * @exit * running listener count = 0
         */
        STARTING,
        /**
         * Start failed, or was cancelled.  From this state, the start may be retried or the service may enter the
         * {@code DOWN} state.
         *
         * @enter all dependencies are UP
         * @exit * running listener count = 0
         * @exit STARTING retry == true
         * @exit DOWN mode is ON_DEMAND and demand count == 0, or mode is NEVER, or a dependency enters STOPPING
         */
        START_FAILED,
        /**
         * Up.
         *
         * @enter all dependencies are UP
         * @exit STOPPING mode is ON_DEMAND and demand count == 0, or mode is NEVER, or a dependency enters STOPPING
         */
        UP,
        /**
         * Service is stopping.  Dependents may not enter the {@code STARTING} state.  This state may not be left until
         * all dependents are {@code DOWN} and the {@code stop} method has finished.
         */
        STOPPING,
        /**
         * Removed from the container.
         *
         * @enter No dependents exist.
         * @enter mode == NEVER
         */
        REMOVED,
        ;
    }

    /**
     * The controller mode for a service.
     */
    enum Mode {
        /**
         * Do not start; in addition, ignore demands from dependents.
         */
        NEVER,
        /**
         * Only come up if all dependencies are satisfied <b>and</b> at least one dependent demands to start.
         */
        ON_DEMAND,
        /**
         * Come up automatically as soon as all dependencies are satisfied.  This is the default mode.
         */
        AUTOMATIC,
        /**
         * Demand to start, recursively demanding dependencies.
         */
        IMMEDIATE,
        ;
    }
}

@@ -3419,302 +3419,8 @@
 wn.%0A
-         *%0A         * @enter all dependents are DOWN%0A         * @exit STARTING all dependencies are UP%0A         * @exit * running listener count = 0%0A         * @exit STARTING mode is IMMEDIATE or AUTOMATIC, or mode is ON_DEMAND and demand count %3E 0%0A         * @exit REMOVED no dependents exist%0A
     
@@ -3635,107 +3635,8 @@
 ed.%0A
-         *%0A         * @enter all dependencies are UP%0A         * @exit * running listener count = 0%0A
     
@@ -3833,480 +3833,58 @@
    *
-%0A         * @enter all dependencies are UP%0A         * @exit * running listener count = 0%0A         * @exit STARTING retry == true%0A         * @exit DOWN mode is ON_DEMAND and demand count == 0, or mode is NEVER, or a dependency enters STOPPING%0A         */%0A        START_FAILED,%0A        /**%0A         * Up.%0A         *%0A         * @enter all dependencies are UP%0A         * @exit STOPPING mode is ON_DEMAND and demand count == 0, or mode is NEVER, or a dependency enters STOPPING
+/%0A        START_FAILED,%0A        /**%0A         * Up.
 %0A   
@@ -4206,90 +4206,8 @@
 er.%0A
-         *%0A         * @enter No dependents exist.%0A         * @enter mode == NEVER%0A
     
@@ -4321,16 +4321,115 @@
 m Mode %7B
+%0A%0A        /**%0A         * Remove this service and all of its dependents.%0A         */%0A        REMOVE,
 %0A       

Add "REMOVE" mode