001    /**
002    * Licensed to the Apache Software Foundation (ASF) under one
003    * or more contributor license agreements.  See the NOTICE file
004    * distributed with this work for additional information
005    * regarding copyright ownership.  The ASF licenses this file
006    * to you under the Apache License, Version 2.0 (the
007    * "License"); you may not use this file except in compliance
008    * with the License.  You may obtain a copy of the License at
009    *
010    *     http://www.apache.org/licenses/LICENSE-2.0
011    *
012    * Unless required by applicable law or agreed to in writing, software
013    * distributed under the License is distributed on an "AS IS" BASIS,
014    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015    * See the License for the specific language governing permissions and
016    * limitations under the License.
017    */
018    
019    package org.apache.hadoop.service;
020    
021    import org.apache.hadoop.classification.InterfaceAudience.Public;
022    import org.apache.hadoop.classification.InterfaceStability.Evolving;
023    import org.apache.hadoop.conf.Configuration;
024    
025    import java.io.Closeable;
026    import java.io.IOException;
027    import java.util.List;
028    import java.util.Map;
029    
030    /**
031     * Service LifeCycle.
032     */
033    @Public
034    @Evolving
035    public interface Service extends Closeable {
036    
037      /**
038       * Service states
039       */
040      public enum STATE {
041        /** Constructed but not initialized */
042        NOTINITED(0, "NOTINITED"),
043    
044        /** Initialized but not started or stopped */
045        INITED(1, "INITED"),
046    
047        /** started and not stopped */
048        STARTED(2, "STARTED"),
049    
050        /** stopped. No further state transitions are permitted */
051        STOPPED(3, "STOPPED");
052    
053        /**
054         * An integer value for use in array lookup and JMX interfaces.
055         * Although {@link Enum#ordinal()} could do this, explicitly
056         * identify the numbers gives more stability guarantees over time.
057         */
058        private final int value;
059    
060        /**
061         * A name of the state that can be used in messages
062         */
063        private final String statename;
064    
065        private STATE(int value, String name) {
066          this.value = value;
067          this.statename = name;
068        }
069    
070        /**
071         * Get the integer value of a state
072         * @return the numeric value of the state
073         */
074        public int getValue() {
075          return value;
076        }
077    
078        /**
079         * Get the name of a state
080         * @return the state's name
081         */
082        @Override
083        public String toString() {
084          return statename;
085        }
086      }
087    
088      /**
089       * Initialize the service.
090       *
091       * The transition MUST be from {@link STATE#NOTINITED} to {@link STATE#INITED}
092       * unless the operation failed and an exception was raised, in which case
093       * {@link #stop()} MUST be invoked and the service enter the state
094       * {@link STATE#STOPPED}.
095       * @param config the configuration of the service
096       * @throws RuntimeException on any failure during the operation
097    
098       */
099      void init(Configuration config);
100    
101    
102      /**
103       * Start the service.
104       *
105       * The transition MUST be from {@link STATE#INITED} to {@link STATE#STARTED}
106       * unless the operation failed and an exception was raised, in which case
107       * {@link #stop()} MUST be invoked and the service enter the state
108       * {@link STATE#STOPPED}.
109       * @throws RuntimeException on any failure during the operation
110       */
111    
112      void start();
113    
114      /**
115       * Stop the service. This MUST be a no-op if the service is already
116       * in the {@link STATE#STOPPED} state. It SHOULD be a best-effort attempt
117       * to stop all parts of the service.
118       *
119       * The implementation must be designed to complete regardless of the service
120       * state, including the initialized/uninitialized state of all its internal
121       * fields.
122       * @throws RuntimeException on any failure during the stop operation
123       */
124      void stop();
125    
126      /**
127       * A version of stop() that is designed to be usable in Java7 closure
128       * clauses.
129       * Implementation classes MUST relay this directly to {@link #stop()}
130       * @throws IOException never
131       * @throws RuntimeException on any failure during the stop operation
132       */
133      void close() throws IOException;
134    
135      /**
136       * Register a listener to the service state change events.
137       * If the supplied listener is already listening to this service,
138       * this method is a no-op.
139       * @param listener a new listener
140       */
141      void registerServiceListener(ServiceStateChangeListener listener);
142    
143      /**
144       * Unregister a previously registered listener of the service state
145       * change events. No-op if the listener is already unregistered.
146       * @param listener the listener to unregister.
147       */
148      void unregisterServiceListener(ServiceStateChangeListener listener);
149    
150      /**
151       * Get the name of this service.
152       * @return the service name
153       */
154      String getName();
155    
156      /**
157       * Get the configuration of this service.
158       * This is normally not a clone and may be manipulated, though there are no
159       * guarantees as to what the consequences of such actions may be
160       * @return the current configuration, unless a specific implentation chooses
161       * otherwise.
162       */
163      Configuration getConfig();
164    
165      /**
166       * Get the current service state
167       * @return the state of the service
168       */
169      STATE getServiceState();
170    
171      /**
172       * Get the service start time
173       * @return the start time of the service. This will be zero if the service
174       * has not yet been started.
175       */
176      long getStartTime();
177    
178      /**
179       * Query to see if the service is in a specific state.
180       * In a multi-threaded system, the state may not hold for very long.
181       * @param state the expected state
182       * @return true if, at the time of invocation, the service was in that state.
183       */
184      boolean isInState(STATE state);
185    
186      /**
187       * Get the first exception raised during the service failure. If null,
188       * no exception was logged
189       * @return the failure logged during a transition to the stopped state
190       */
191      Throwable getFailureCause();
192    
193      /**
194       * Get the state in which the failure in {@link #getFailureCause()} occurred.
195       * @return the state or null if there was no failure
196       */
197      STATE getFailureState();
198    
199      /**
200       * Block waiting for the service to stop; uses the termination notification
201       * object to do so.
202       *
203       * This method will only return after all the service stop actions
204       * have been executed (to success or failure), or the timeout elapsed
205       * This method can be called before the service is inited or started; this is
206       * to eliminate any race condition with the service stopping before
207       * this event occurs.
208       * @param timeout timeout in milliseconds. A value of zero means "forever"
209       * @return true iff the service stopped in the time period
210       */
211      boolean waitForServiceToStop(long timeout);
212    
213      /**
214       * Get a snapshot of the lifecycle history; it is a static list
215       * @return a possibly empty but never null list of lifecycle events.
216       */
217      public List<LifecycleEvent> getLifecycleHistory();
218    
219      /**
220       * Get the blockers on a service -remote dependencies
221       * that are stopping the service from being <i>live</i>.
222       * @return a (snapshotted) map of blocker name-&gt;description values
223       */
224      public Map<String, String> getBlockers();
225    }