Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ExecutorManagerFactory |
|
| 2.3;2,3 | ||||
ExecutorManagerFactory$1 |
|
| 2.3;2,3 |
1 | /* | |
2 | * This file is part of AceLogger. | |
3 | * | |
4 | * AceLogger is free software: you can redistribute it and/or modify it under the terms of the GNU | |
5 | * Lesser General Public License as published by the Free Software Foundation, either version 3 of | |
6 | * the License, or (at your option) any later version. | |
7 | * | |
8 | * AceLogger is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without | |
9 | * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
10 | * Lesser General Public License for more details. | |
11 | * | |
12 | * You should have received a copy of the GNU Lesser General Public License along with AceLogger. | |
13 | * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>. | |
14 | */ | |
15 | package net.sourceforge.acelogger.factory; | |
16 | ||
17 | import java.util.ArrayList; | |
18 | import java.util.HashMap; | |
19 | import java.util.List; | |
20 | import java.util.Map; | |
21 | import java.util.concurrent.CountDownLatch; | |
22 | import java.util.concurrent.TimeUnit; | |
23 | ||
24 | import net.sourceforge.acelogger.constants.ExecutorManagerConstants; | |
25 | import net.sourceforge.acelogger.execution.LogController; | |
26 | import net.sourceforge.acelogger.execution.TerminationException; | |
27 | import net.sourceforge.acelogger.execution.manager.ExecutorManager; | |
28 | ||
29 | /** | |
30 | * Factory for managing instances of configured executor managers. | |
31 | * | |
32 | * @author Zardi (https://sourceforge.net/users/daniel_zardi) | |
33 | * @version 1.0.0 | |
34 | * @since 1.0.0 | |
35 | */ | |
36 | public final class ExecutorManagerFactory { | |
37 | ||
38 | /** | |
39 | * A instance of this class (the only one). | |
40 | */ | |
41 | 1 | private static final ExecutorManagerFactory INSTANCE = new ExecutorManagerFactory(); |
42 | ||
43 | /** | |
44 | * Used when no configured manager is found for a given identifier. | |
45 | */ | |
46 | private ExecutorManager defaultExecutorManager; | |
47 | ||
48 | /** | |
49 | * Maps each configured manager to a unique identifier. | |
50 | */ | |
51 | private final Map<String, ExecutorManager> registeredExecutors; | |
52 | ||
53 | /** | |
54 | * Indicates if this factory has ordered all of its managers a shutdown or not. | |
55 | */ | |
56 | 1 | private boolean shutdown = false; |
57 | ||
58 | /** | |
59 | * Creates a new ExecutorManagerFactory (This class is a singleton). | |
60 | * | |
61 | * @since 1.0.0 | |
62 | */ | |
63 | 1 | private ExecutorManagerFactory() { |
64 | 1 | registeredExecutors = new HashMap<String, ExecutorManager>(); |
65 | 1 | defaultExecutorManager = ExecutorManagerConstants.EMPTY; |
66 | 1 | } |
67 | ||
68 | /** | |
69 | * Obtains a properly configured manager for the given identifier. | |
70 | * | |
71 | * @param identifier | |
72 | * The identifier of the intended manager. | |
73 | * @return A properly configured manager for the given identifier. If the identifier is not | |
74 | * found, then the default manager is returned. | |
75 | * @see ExecutorManagerFactory#getDefaultExecutorManager() | |
76 | * @since 1.0.0 | |
77 | */ | |
78 | public static ExecutorManager getExecutorManager(String identifier) { | |
79 | 0 | LogController.ensureInitialization(); |
80 | 0 | ExecutorManager intendedExecutor = INSTANCE.registeredExecutors.get(identifier); |
81 | 0 | if (intendedExecutor == null) { |
82 | 0 | int lastDotIndex = identifier.lastIndexOf('.'); |
83 | 0 | if (lastDotIndex > 0) { |
84 | 0 | intendedExecutor = getExecutorManager(identifier.substring(0, lastDotIndex)); |
85 | } else { | |
86 | 0 | intendedExecutor = INSTANCE.defaultExecutorManager; |
87 | } | |
88 | } | |
89 | 0 | return intendedExecutor; |
90 | } | |
91 | ||
92 | /** | |
93 | * Sets the default manager of this factory, the one used when no manager is found for a given | |
94 | * identifier. | |
95 | * | |
96 | * @param manager | |
97 | * The manager that will be used as the default one from now. | |
98 | * @return The previous default manager. | |
99 | * @since 1.0.0 | |
100 | */ | |
101 | public static ExecutorManager setDefaultExecutorManager(ExecutorManager manager) { | |
102 | 0 | LogController.ensureInitialization(); |
103 | 0 | ExecutorManager previous = INSTANCE.defaultExecutorManager; |
104 | 0 | if (manager != null) { |
105 | 0 | INSTANCE.defaultExecutorManager = manager; |
106 | } | |
107 | 0 | return previous; |
108 | } | |
109 | ||
110 | /** | |
111 | * Returns the default manager of this factory, the one used when no manager is found for a | |
112 | * given identifier. | |
113 | * | |
114 | * @return The default manager. | |
115 | * @since 1.0.0 | |
116 | */ | |
117 | public static ExecutorManager getDefaultExecutorManager() { | |
118 | 1 | LogController.ensureInitialization(); |
119 | 1 | return INSTANCE.defaultExecutorManager; |
120 | } | |
121 | ||
122 | /** | |
123 | * Registers an appender within this factory. The mapped identifier will be the managers | |
124 | * identifier. | |
125 | * | |
126 | * @param manager | |
127 | * The manager to be registered. | |
128 | * @return The default manager if there was no previous mapping for the identifier or the | |
129 | * previous configured manager otherwise. | |
130 | * @see ExecutorManagerFactory#getDefaultExecutorManager() | |
131 | * @since 1.0.0 | |
132 | */ | |
133 | public static ExecutorManager registerExecutorManager(ExecutorManager manager) { | |
134 | 5 | LogController.ensureInitialization(); |
135 | 5 | ExecutorManager intendedExecutor = null; |
136 | 5 | if (manager != null) { |
137 | 4 | intendedExecutor = INSTANCE.registeredExecutors.put(manager.getIdentifier(), manager); |
138 | } | |
139 | 5 | if (intendedExecutor == null) { |
140 | 5 | intendedExecutor = INSTANCE.defaultExecutorManager; |
141 | } | |
142 | 5 | return intendedExecutor; |
143 | } | |
144 | ||
145 | /** | |
146 | * Returns a list of all managers registered in this factory. | |
147 | * | |
148 | * @return A list of managers. | |
149 | * @since 1.0.0 | |
150 | */ | |
151 | public static List<ExecutorManager> getRegisteredExecutorManagers() { | |
152 | 5 | LogController.ensureInitialization(); |
153 | 5 | List<ExecutorManager> allExecutorManagers = new ArrayList<ExecutorManager>( |
154 | INSTANCE.registeredExecutors.values()); | |
155 | 5 | return allExecutorManagers; |
156 | } | |
157 | ||
158 | /** | |
159 | * Indicates if this factory has ordered all of its managers a shutdown or not. If this factory | |
160 | * has ordered shutdown, it is not safe to execute any task. | |
161 | * | |
162 | * @return True id the shutdown was previously ordered, false otherwise. | |
163 | * @since 1.0.0 | |
164 | */ | |
165 | public static boolean isShutdown() { | |
166 | 0 | LogController.ensureInitialization(); |
167 | 0 | return INSTANCE.shutdown; |
168 | } | |
169 | ||
170 | /** | |
171 | * Shuts down each of the registered executor managers, this should be called to guarantee that | |
172 | * all tasks submitted will be run before termination. | |
173 | * | |
174 | * @return True if all executors finished their tasks properly, false if there are tasks under | |
175 | * or awaiting execution. | |
176 | * @since 1.0.0 | |
177 | */ | |
178 | public static boolean doProperExecutorManagersShutdown() { | |
179 | 1 | if (INSTANCE.shutdown) { |
180 | 0 | throw new IllegalStateException(""); |
181 | } else { | |
182 | 1 | LogController.ensureInitialization(); |
183 | 1 | INSTANCE.shutdown = true; |
184 | 1 | boolean properShutdown = true; |
185 | 1 | List<ExecutorManager> allExecutorManagers = getRegisteredExecutorManagers(); |
186 | 1 | for (ExecutorManager currentExecutorManager : allExecutorManagers) { |
187 | 4 | currentExecutorManager.orderProperShutdown(); |
188 | 4 | properShutdown &= currentExecutorManager.isTerminated(); |
189 | } | |
190 | 1 | return properShutdown; |
191 | } | |
192 | } | |
193 | ||
194 | /** | |
195 | * Awaits for the execution of the remaining tasks in executor managers registered in this | |
196 | * factory. This method should be called after ordering a proper shutdown of the executors. | |
197 | * | |
198 | * @param terminationTimeout | |
199 | * The maximum time (in ms) to wait while executing the remaining tasks. | |
200 | * @return True if all executor managers terminated execution of its tasks before the supplied | |
201 | * timeout; False otherwise. | |
202 | * @throws TerminationException | |
203 | * if interrupted while waiting for managers to shutdown. | |
204 | * @since 1.0.0 | |
205 | * @see ExecutorManagerFactory#doProperExecutorManagersShutdown() | |
206 | */ | |
207 | public static boolean awaitExecutorManagersShutdown(final long terminationTimeout) | |
208 | throws TerminationException { | |
209 | 0 | boolean allDone = false; |
210 | 0 | if (INSTANCE.shutdown) { |
211 | 0 | List<ExecutorManager> remainingExecutorManagers = getRegisteredExecutorManagers(); |
212 | 0 | final CountDownLatch synchronizer = |
213 | new CountDownLatch(remainingExecutorManagers.size()); | |
214 | 0 | for (final ExecutorManager currentManager : remainingExecutorManagers) { |
215 | 0 | LogController.submitBackgroundTask(new Runnable() { |
216 | /** | |
217 | * Orders the termination of each manager under a given timeout. | |
218 | */ | |
219 | public void run() { | |
220 | 0 | currentManager.awaitTermination(terminationTimeout); |
221 | 0 | synchronizer.countDown(); |
222 | 0 | } |
223 | }); | |
224 | } | |
225 | try { | |
226 | 0 | allDone = synchronizer.await(terminationTimeout, TimeUnit.MILLISECONDS); |
227 | 0 | } catch (InterruptedException e) { |
228 | 0 | throw new TerminationException("Interrupted while waiting executor to finish", e); |
229 | 0 | } |
230 | 0 | } else { |
231 | 0 | throw new IllegalStateException( |
232 | "Can only await executor managers shutdown after calling" | |
233 | + " doProperExecutorManagersShutdown"); | |
234 | } | |
235 | 0 | return allDone; |
236 | } | |
237 | ||
238 | } |