View Javadoc

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  	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  	private boolean shutdown = false;
57  
58  	/**
59  	 * Creates a new ExecutorManagerFactory (This class is a singleton).
60  	 * 
61  	 * @since 1.0.0
62  	 */
63  	private ExecutorManagerFactory() {
64  		registeredExecutors = new HashMap<String, ExecutorManager>();
65  		defaultExecutorManager = ExecutorManagerConstants.EMPTY;
66  	}
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  		LogController.ensureInitialization();
80  		ExecutorManager intendedExecutor = INSTANCE.registeredExecutors.get(identifier);
81  		if (intendedExecutor == null) {
82  			int lastDotIndex = identifier.lastIndexOf('.');
83  			if (lastDotIndex > 0) {
84  				intendedExecutor = getExecutorManager(identifier.substring(0, lastDotIndex));
85  			} else {
86  				intendedExecutor = INSTANCE.defaultExecutorManager;
87  			}
88  		}
89  		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 		LogController.ensureInitialization();
103 		ExecutorManager previous = INSTANCE.defaultExecutorManager;
104 		if (manager != null) {
105 			INSTANCE.defaultExecutorManager = manager;
106 		}
107 		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 		LogController.ensureInitialization();
119 		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 		LogController.ensureInitialization();
135 		ExecutorManager intendedExecutor = null;
136 		if (manager != null) {
137 			intendedExecutor = INSTANCE.registeredExecutors.put(manager.getIdentifier(), manager);
138 		}
139 		if (intendedExecutor == null) {
140 			intendedExecutor = INSTANCE.defaultExecutorManager;
141 		}
142 		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 		LogController.ensureInitialization();
153 		List<ExecutorManager> allExecutorManagers = new ArrayList<ExecutorManager>(
154 				INSTANCE.registeredExecutors.values());
155 		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 		LogController.ensureInitialization();
167 		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 		if (INSTANCE.shutdown) {
180 			throw new IllegalStateException("");
181 		} else {
182 			LogController.ensureInitialization();
183 			INSTANCE.shutdown = true;
184 			boolean properShutdown = true;
185 			List<ExecutorManager> allExecutorManagers = getRegisteredExecutorManagers();
186 			for (ExecutorManager currentExecutorManager : allExecutorManagers) {
187 				currentExecutorManager.orderProperShutdown();
188 				properShutdown &= currentExecutorManager.isTerminated();
189 			}
190 			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 		boolean allDone = false;
210 		if (INSTANCE.shutdown) {
211 			List<ExecutorManager> remainingExecutorManagers = getRegisteredExecutorManagers();
212 			final CountDownLatch synchronizer =
213 					new CountDownLatch(remainingExecutorManagers.size());
214 			for (final ExecutorManager currentManager : remainingExecutorManagers) {
215 				LogController.submitBackgroundTask(new Runnable() {
216 					/**
217 					 * Orders the termination of each manager under a given timeout.
218 					 */
219 					public void run() {
220 						currentManager.awaitTermination(terminationTimeout);
221 						synchronizer.countDown();
222 					}
223 				});
224 			}
225 			try {
226 				allDone = synchronizer.await(terminationTimeout, TimeUnit.MILLISECONDS);
227 			} catch (InterruptedException e) {
228 				throw new TerminationException("Interrupted while waiting executor to finish", e);
229 			}
230 		} else {
231 			throw new IllegalStateException(
232 					"Can only await executor managers shutdown after calling"
233 					+ " doProperExecutorManagersShutdown");
234 		}
235 		return allDone;
236 	}
237 
238 }