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 }