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