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.AbstractLifecycle;
13 
14 import core.atomic;
15 
16 import hunt.util.Lifecycle;
17 import hunt.util.Common;
18 import hunt.util.Runnable;
19 import hunt.logging;
20 
21 
22 /**
23  * Interface for objects that may participate in a phased
24  * process such as lifecycle management.
25  *
26  * @see SmartLifecycle
27  */
28 interface Phased {
29 
30 	/**
31 	 * Return the phase value of this object.
32 	 */
33 	int getPhase();
34 }
35 
36 
37 /**
38  * An extension of the {@link Lifecycle} interface for those objects that require to
39  * be started upon ApplicationContext refresh and/or shutdown in a particular order.
40  * The {@link #isAutoStartup()} return value indicates whether this object should
41  * be started at the time of a context refresh. The callback-accepting
42  * {@link #stop(Runnable)} method is useful for objects that have an asynchronous
43  * shutdown process. Any implementation of this interface <i>must</i> invoke the
44  * callback's {@code run()} method upon shutdown completion to avoid unnecessary
45  * delays in the overall ApplicationContext shutdown.
46  *
47  * <p>This interface extends {@link Phased}, and the {@link #getPhase()} method's
48  * return value indicates the phase within which this Lifecycle component should
49  * be started and stopped. The startup process begins with the <i>lowest</i> phase
50  * value and ends with the <i>highest</i> phase value ({@code Integer.MIN_VALUE}
51  * is the lowest possible, and {@code Integer.MAX_VALUE} is the highest possible).
52  * The shutdown process will apply the reverse order. Any components with the
53  * same value will be arbitrarily ordered within the same phase.
54  *
55  * <p>Example: if component B depends on component A having already started,
56  * then component A should have a lower phase value than component B. During
57  * the shutdown process, component B would be stopped before component A.
58  *
59  * <p>Any explicit "depends-on" relationship will take precedence over the phase
60  * order such that the dependent bean always starts after its dependency and
61  * always stops before its dependency.
62  *
63  * <p>Any {@code Lifecycle} components within the context that do not also
64  * implement {@code SmartLifecycle} will be treated as if they have a phase
65  * value of 0. That way a {@code SmartLifecycle} implementation may start
66  * before those {@code Lifecycle} components if it has a negative phase value,
67  * or it may start after those components if it has a positive phase value.
68  *
69  * <p>Note that, due to the auto-startup support in {@code SmartLifecycle}, a
70  * {@code SmartLifecycle} bean instance will usually get initialized on startup
71  * of the application context in any case. As a consequence, the bean definition
72  * lazy-init flag has very limited actual effect on {@code SmartLifecycle} beans.
73  *
74  * @author Mark Fisher
75  */
76 interface SmartLifecycle : Lifecycle, Phased {
77 
78 	/**
79 	 * Returns {@code true} if this {@code Lifecycle} component should get
80 	 * started automatically by the container at the time that the containing
81 	 * {@link ApplicationContext} gets refreshed.
82 	 * <p>A value of {@code false} indicates that the component is intended to
83 	 * be started through an explicit {@link #start()} call instead, analogous
84 	 * to a plain {@link Lifecycle} implementation.
85 	 * @see #start()
86 	 * @see #getPhase()
87 	 */
88 	bool isAutoStartup();
89 
90 	/**
91 	 * Indicates that a Lifecycle component must stop if it is currently running.
92 	 * <p>The provided callback is used by the {@link LifecycleProcessor} to support
93 	 * an ordered, and potentially concurrent, shutdown of all components having a
94 	 * common shutdown order value. The callback <b>must</b> be executed after
95 	 * the {@code SmartLifecycle} component does indeed stop.
96 	 * <p>The {@link LifecycleProcessor} will call <i>only</i> this variant of the
97 	 * {@code stop} method; i.e. {@link Lifecycle#stop()} will not be called for
98 	 * {@code SmartLifecycle} implementations unless explicitly delegated to within
99 	 * the implementation of this method.
100 	 * @see #stop()
101 	 * @see #getPhase()
102 	 */
103 	void stop(Runnable callback);
104 
105     alias stop = Lifecycle.stop;
106 
107 	int getPhase();
108 
109 }
110 
111 /**
112 */
113 abstract class AbstractLifecycle : Lifecycle {
114 
115     protected shared bool _isRunning;
116 
117     this() {
118        
119     }
120 
121     bool isRunning() {
122         return _isRunning;
123     }
124 
125     bool isStopped() {
126         return !_isRunning;
127     }
128 
129     void start() {
130         if (cas(&_isRunning, false, true)) {
131 			initialize();
132         } else {
133 			version(HUNT_DEBUG) warning("Starting repeatedly!");
134 		}
135     }
136 
137     void stop() {
138         if (cas(&_isRunning, true, false)) {
139 			destroy();
140         } else {
141 			version(HUNT_DEBUG) warning("Stopping repeatedly!");
142 		}
143     }
144 
145     abstract protected void initialize();
146 
147     abstract protected void destroy();
148 }