-
Notifications
You must be signed in to change notification settings - Fork 8
/
RestartableHolder.java
127 lines (114 loc) · 4.09 KB
/
RestartableHolder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package nl.pim16aap2.animatedarchitecture.core.api.restartable;
import lombok.extern.flogger.Flogger;
import nl.pim16aap2.animatedarchitecture.core.api.debugging.IDebuggable;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
/**
* Represents an object that can issue a restart or shutdown to {@link IRestartable} objects.
*/
@Flogger
public final class RestartableHolder implements IDebuggable
{
private final Set<IRestartable> restartables = new LinkedHashSet<>();
private int shutdownCount = 0;
private int initCount = 0;
/**
* Register a {@link IRestartable} object with this object, so this object can restart the provided object.
*
* @param restartable
* A {@link IRestartable} object that can be restarted by this object.
* @throws NullPointerException
* If the provided restartable is null.
*/
public void registerRestartable(IRestartable restartable)
{
restartables.add(Objects.requireNonNull(restartable, "Cannot register null restartable!"));
}
/**
* Checks if a {@link IRestartable} has been registered with this object.
*
* @param restartable
* The {@link IRestartable} to check.
* @return True if the {@link IRestartable} has been registered with this object.
*/
@SuppressWarnings("unused")
public boolean isRestartableRegistered(@Nullable IRestartable restartable)
{
if (restartable == null)
return false;
return restartables.contains(restartable);
}
/**
* Deregisters an {@link IRestartable} if it is currently registered.
*
* @param restartable
* The {@link IRestartable} to deregister.
* @throws NullPointerException
* If the provided restartable is null.
*/
public void deregisterRestartable(IRestartable restartable)
{
restartables.remove(Objects.requireNonNull(restartable, "Cannot deregister null restartable!"));
}
/**
* Restarts all {@link #restartables}.
* <p>
* This is the same as manually calling {@link #shutDown()} and then {@link #initialize()}.
*/
public void restart()
{
shutDown();
initialize();
}
/**
* Calls {@link IRestartable#initialize()} for all registered {@link IRestartable}s.
*/
public void initialize()
{
this.initCount += 1;
restartables.forEach(restartable -> runForRestartable("initialize", IRestartable::initialize, restartable));
}
/**
* Calls {@link IRestartable#shutDown()} for all registered {@link IRestartable}s.
* <p>
* The {@link #restartables} are shut down in reverse order to ensure that dependents are processed before their
* dependencies are.
*/
public void shutDown()
{
this.shutdownCount += 1;
final IRestartable[] arr = restartables.toArray(new IRestartable[0]);
for (int idx = arr.length - 1; idx >= 0; --idx)
runForRestartable("shut down", IRestartable::shutDown, arr[idx]);
}
private static void runForRestartable(String actionName, Consumer<IRestartable> action, IRestartable restartable)
{
try
{
action.accept(restartable);
}
catch (Exception e)
{
log.atSevere().withCause(e).log(
"Failed to %s restartable of type %s:\n%s",
actionName,
restartable.getClass().getName(),
restartable
);
}
}
@Override
public String getDebugInformation()
{
final var sb = new StringBuilder()
.append("Number of Registered Restartables: ").append(restartables.size()).append('\n')
.append("ShutDownCount: ").append(shutdownCount).append('\n')
.append("InitCount: ").append(initCount).append('\n')
.append("Registered Restartables:\n");
restartables.forEach(restartable -> sb.append(" - ").append(restartable.getClass().getName()).append('\n'));
return sb.toString();
}
}