/* * * * Copyright (c) 2016. David Sowerby * * * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * * the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * * specific language governing permissions and limitations under the License. * */ package uk.q3c.krail.core.services; import uk.q3c.krail.core.i18n.NamedAndDescribed; /** * Implement this interface to provide a Service. A Service is typically something which is wired up using Guice * modules, but requires logic to get fully up and running, or consumes external resources - database connections, web * services etc, and is based on the recommendations of the Guice team. (see * https://code.google.com/p/google-guice/wiki/ModulesShouldBeFastAndSideEffectFree). * <p> * A {@link Service} can however be used for anything you feel appropriate, which could benefit from having a two stage * creation cycle - the initial configuration through Guice modules, followed by a controlled start to activate / * consume resources. * <p> * The easiest way is to create an implementation is to sub-class either {@link AbstractService}.<br> * Dependencies between services shold not be coded directly but use the features described in {@link ServicesGraph} * <p> * Implementations (even sub-classes of {@link AbstractService} must define a key which when combined with {@link #getInstanceNumber()}, provides a unique * identity for this Service. It is an I18NKey because it is expected that this name will be presented to end users (even if only to application sys * admins) * <p> * When an instance of a {@link Service} implementation is created through Guice, it is automatically registered with * the {@link DefaultServicesMonitor}. (This is done through a Guice listener in the {@link ServicesModule}). * <p> * The AOP code in the ServicesMonitorModule also intercepts the finalize() method, and calls the stop() method to * ensure a service is stopped before being finalized. * <p> * A service should have the following characteristics: * <ol> * <li>All Services must be instantiated through Guice * <li>Other {@link Service} instances which your Service depends on, must be injected through the constructor * <li>The constructor must be lightweight and must not require that its dependencies are already started at the time * of injection. * <li>If the dependency's constructor is lightweight as it should be, it should also be unnecessary to inject a Provider<Service> * </ol> * Details of the lifecycle can be found at http://krail.readthedocs.org/en/master/devguide-services/ * * @author David Sowerby */ public interface Service extends NamedAndDescribed { enum State { INITIAL, STARTING, RUNNING, STOPPING, STOPPED, RESETTING, FAILED } enum Cause { FAILED, STOPPED, FAILED_TO_START, FAILED_TO_STOP, DEPENDENCY_STOPPED, STARTED, DEPENDENCY_FAILED, FAILED_TO_RESET, RESET } /** * You will only need to implement this if you are not using a sub-class of * {@link AbstractService}. When you do sub-class {@link AbstractService}, override {@link AbstractService#doStart()}. Exceptions should be caught and * handled within the implementation of this method - generally this will set the cause to {@link Cause#FAILED_TO_START} * * @throws ServiceStatusException if called when service is currently in a state which does not allow a start */ ServiceStatus start(); /** * Equivalent to calling * {@link #stop(Cause)} with a value of {@link State#STOPPED}. Implementations must handle all exceptions and set the state to {@link Cause#FAILED_TO_STOP} */ ServiceStatus stop(); /** * Attempts to stop the Service, and sets the state to * {@link Cause#FAILED}. Implementations must handle all exceptions and if appropriate set cause to {@link Cause#FAILED_TO_STOP} * * @return state after the call */ ServiceStatus fail(); /** * You will only need to implement this if you are not using a sub-class of {@link AbstractService}. When you do sub-class {@link AbstractService}, * override {@link AbstractService#doStop()}. Implementations must handle all exceptions and set the state to {@link State#STOPPED} and Cause appropriately * * @param cause the caller uses this to indicate the cause of the stop. * * valid. These * mean:<ol><li>STOPPED: the user elected to stop this Service directly</li><li>DEPENDENCY_STOPPED: A dependency which this Service * needs in order * to run, has stopped</li><li>DEPENDENCY_FAILED: A dependency which this Service needs in order to run, has failed</li></ol>: */ ServiceStatus stop(Cause cause); /** * Returns the translated description for this service, or an empty String if no description as been set * * @return The translated description for this service, or an empty String if no description as been set */ String getDescription(); /** * returns the State value for this service instance * * @return the State value for this service instance */ State getState(); /** * Returns the cause of the last state change * * @return Returns the cause of the last state change */ Cause getCause(); /** * Returns true if and only if status == Service.Status.STARTED) * * @return true if and only if status == Service.Status.STARTED) */ boolean isStarted(); /** * Returns true if the service is in a stopped state * * @return true if the service is in a stopped state */ boolean isStopped(); /** * Notify this service that one of its required dependencies has failed * * @return the resultant {@link ServiceStatus} */ ServiceStatus dependencyFail(); /** * Notify this service that one of its required dependencies has stopped * * @return the resultant {@link ServiceStatus} */ ServiceStatus dependencyStop(); default ServiceKey getServiceKey() { return new ServiceKey(getNameKey()); } /** * Not used by default, but can be used to identify a specific instance of a {@link Service} * * @return 0 by default */ int getInstanceNumber(); /** * /** * Not used by default, but can be used to identify a specific instance of a {@link Service} * * @param instance number to set */ void setInstanceNumber(int instance); /** * Resets a service from a stopped or failed state to INITIAL. Does nothing if the service is STARTED, STARTING or STOPPING * * @return a ServiceStatus of INITIAL */ ServiceStatus reset(); }