1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.util.Lifecycle;
13 
14 import core.atomic;
15 
16 import hunt.util.Common;
17 import hunt.logging.ConsoleLogger;
18 
19 /**
20  * A common interface defining methods for start/stop lifecycle control.
21  * The typical use case for this is to control asynchronous processing.
22  * <b>NOTE: This interface does not imply specific auto-startup semantics.
23  * Consider implementing {@link SmartLifecycle} for that purpose.</b>
24  *
25  * <p>Can be implemented by both components (typically a Spring bean defined in a
26  * Spring context) and containers  (typically a Spring {@link ApplicationContext}
27  * itself). Containers will propagate start/stop signals to all components that
28  * apply within each container, e.g. for a stop/restart scenario at runtime.
29  *
30  * <p>Can be used for direct invocations or for management operations via JMX.
31  * In the latter case, the {@link org.springframework.jmx.export.MBeanExporter}
32  * will typically be defined with an
33  * {@link org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler},
34  * restricting the visibility of activity-controlled components to the Lifecycle
35  * interface.
36  *
37  * <p>Note that the present {@code Lifecycle} interface is only supported on
38  * <b>top-level singleton beans</b>. On any other component, the {@code Lifecycle}
39  * interface will remain undetected and hence ignored. Also, note that the extended
40  * {@link SmartLifecycle} interface provides sophisticated integration with the
41  * application context's startup and shutdown phases.
42  *
43  * @see SmartLifecycle
44  */
45 interface Lifecycle {
46 	/**
47 	 * Start this component.
48 	 * <p>Should not throw an exception if the component is already running.
49 	 * <p>In the case of a container, this will propagate the start signal to all
50 	 * components that apply.
51 	 */    
52 	void start();
53 
54 	/**
55 	 * Stop this component, typically in a synchronous fashion, such that the component is
56 	 * fully stopped upon return of this method. Consider implementing {@link SmartLifecycle}
57 	 * and its {@code stop(Runnable)} variant when asynchronous stop behavior is necessary.
58 	 * <p>Note that this stop notification is not guaranteed to come before destruction:
59 	 * On regular shutdown, {@code Lifecycle} beans will first receive a stop notification
60 	 * before the general destruction callbacks are being propagated; however, on hot
61 	 * refresh during a context's lifetime or on aborted refresh attempts, a given bean's
62 	 * destroy method will be called without any consideration of stop signals upfront.
63 	 * <p>Should not throw an exception if the component is not running (not started yet).
64 	 * <p>In the case of a container, this will propagate the stop signal to all components
65 	 * that apply.
66 	 * @see SmartLifecycle#stop(Runnable)
67 	 */
68 	void stop();
69 
70 
71 	/**
72 	 * Check whether this component is currently running.
73 	 * <p>In the case of a container, this will return {@code true} only if <i>all</i>
74 	 * components that apply are currently running.
75 	 * @return whether the component is currently running
76 	 */
77 	bool isRunning();
78 }
79 
80 
81 /**
82  * Interface for objects that may participate in a phased
83  * process such as lifecycle management.
84  *
85  * @see SmartLifecycle
86  */
87 interface Phased {
88 
89 	/**
90 	 * Return the phase value of this object.
91 	 */
92 	int getPhase();
93 }
94 
95 
96 /**
97  * An extension of the {@link Lifecycle} interface for those objects that require to
98  * be started upon ApplicationContext refresh and/or shutdown in a particular order.
99  * The {@link #isAutoStartup()} return value indicates whether this object should
100  * be started at the time of a context refresh. The callback-accepting
101  * {@link #stop(Runnable)} method is useful for objects that have an asynchronous
102  * shutdown process. Any implementation of this interface <i>must</i> invoke the
103  * callback's {@code run()} method upon shutdown completion to avoid unnecessary
104  * delays in the overall ApplicationContext shutdown.
105  *
106  * <p>This interface extends {@link Phased}, and the {@link #getPhase()} method's
107  * return value indicates the phase within which this Lifecycle component should
108  * be started and stopped. The startup process begins with the <i>lowest</i> phase
109  * value and ends with the <i>highest</i> phase value ({@code Integer.MIN_VALUE}
110  * is the lowest possible, and {@code Integer.MAX_VALUE} is the highest possible).
111  * The shutdown process will apply the reverse order. Any components with the
112  * same value will be arbitrarily ordered within the same phase.
113  *
114  * <p>Example: if component B depends on component A having already started,
115  * then component A should have a lower phase value than component B. During
116  * the shutdown process, component B would be stopped before component A.
117  *
118  * <p>Any explicit "depends-on" relationship will take precedence over the phase
119  * order such that the dependent bean always starts after its dependency and
120  * always stops before its dependency.
121  *
122  * <p>Any {@code Lifecycle} components within the context that do not also
123  * implement {@code SmartLifecycle} will be treated as if they have a phase
124  * value of 0. That way a {@code SmartLifecycle} implementation may start
125  * before those {@code Lifecycle} components if it has a negative phase value,
126  * or it may start after those components if it has a positive phase value.
127  *
128  * <p>Note that, due to the auto-startup support in {@code SmartLifecycle}, a
129  * {@code SmartLifecycle} bean instance will usually get initialized on startup
130  * of the application context in any case. As a consequence, the bean definition
131  * lazy-init flag has very limited actual effect on {@code SmartLifecycle} beans.
132  *
133  * @author Mark Fisher
134  */
135 interface SmartLifecycle : Lifecycle, Phased {
136 
137 	/**
138 	 * Returns {@code true} if this {@code Lifecycle} component should get
139 	 * started automatically by the container at the time that the containing
140 	 * {@link ApplicationContext} gets refreshed.
141 	 * <p>A value of {@code false} indicates that the component is intended to
142 	 * be started through an explicit {@link #start()} call instead, analogous
143 	 * to a plain {@link Lifecycle} implementation.
144 	 * @see #start()
145 	 * @see #getPhase()
146 	 */
147 	bool isAutoStartup();
148 
149 	/**
150 	 * Indicates that a Lifecycle component must stop if it is currently running.
151 	 * <p>The provided callback is used by the {@link LifecycleProcessor} to support
152 	 * an ordered, and potentially concurrent, shutdown of all components having a
153 	 * common shutdown order value. The callback <b>must</b> be executed after
154 	 * the {@code SmartLifecycle} component does indeed stop.
155 	 * <p>The {@link LifecycleProcessor} will call <i>only</i> this variant of the
156 	 * {@code stop} method; i.e. {@link Lifecycle#stop()} will not be called for
157 	 * {@code SmartLifecycle} implementations unless explicitly delegated to within
158 	 * the implementation of this method.
159 	 * @see #stop()
160 	 * @see #getPhase()
161 	 */
162 	void stop(Runnable callback);
163 
164     alias stop = Lifecycle.stop;
165 
166 	int getPhase();
167 
168 }
169 
170 /**
171 */
172 abstract class AbstractLifecycle : Lifecycle {
173 
174     protected shared bool _isRunning;
175 
176     this() {
177        
178     }
179 
180     bool isRunning() {
181         return _isRunning;
182     }
183 
184     bool isStopped() {
185         return !_isRunning;
186     }
187 
188     void start() {
189         if (cas(&_isRunning, false, true)) {
190 			initialize();
191         } else {
192 			version(HUNT_DEBUG) warning("Starting repeatedly!");
193 		}
194     }
195 
196     void stop() {
197         if (cas(&_isRunning, true, false)) {
198 			destroy();
199         } else {
200 			version(HUNT_DEBUG) warning("Stopping repeatedly!");
201 		}
202     }
203 
204     abstract protected void initialize();
205 
206     abstract protected void destroy();
207 }