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.execution;
16  
17  import java.lang.Thread.UncaughtExceptionHandler;
18  import java.util.ArrayList;
19  import java.util.List;
20  import java.util.concurrent.atomic.AtomicBoolean;
21  
22  import net.sourceforge.acelogger.GenericLogger;
23  import net.sourceforge.acelogger.Logger;
24  import net.sourceforge.acelogger.appender.Appender;
25  import net.sourceforge.acelogger.appender.SystemErrAppender;
26  import net.sourceforge.acelogger.constants.LevelFilterConstants;
27  import net.sourceforge.acelogger.execution.manager.ExecutorManager;
28  import net.sourceforge.acelogger.execution.manager.PooledExecutorManager;
29  import net.sourceforge.acelogger.execution.manager.QueuedExecutorManager;
30  import net.sourceforge.acelogger.execution.task.MonitorableTask;
31  import net.sourceforge.acelogger.execution.task.NotifiableTask;
32  import net.sourceforge.acelogger.factory.ExecutorManagerFactory;
33  import net.sourceforge.acelogger.factory.LoggerFactory;
34  import net.sourceforge.acelogger.formatter.Formatter;
35  import net.sourceforge.acelogger.formatter.SimpleFormatter;
36  import net.sourceforge.acelogger.level.filter.LevelFilter;
37  import net.sourceforge.acelogger.location.gatherer.FullLocationGatherer;
38  import net.sourceforge.acelogger.location.gatherer.LocationGatherer;
39  import net.sourceforge.acelogger.location.resolver.InternalCodeFrameResolver;
40  
41  // FIXME: Holy Crap... Design this properly. It started as a workaround, but looks promising now.
42  /**
43   * TODO: Create Doc.
44   * 
45   * @author Zardi (https://sourceforge.net/users/daniel_zardi)
46   * @version 1.0.0
47   * @since 1.0.0
48   */
49  public final class LogController {
50  
51  	private static final int DEFAULT_POOL_SIZE = 3;
52  
53  	private static final long SETUP_TIMEOUT = 10000;
54  
55  	private static final long TERMINATION_TIMEOUT = 10000;
56  
57  	private static final LogController INSTANCE = new LogController();
58  
59  	private List<Runnable> commandsBeforeShutdown;
60  
61  	private ExecutorManager backgroundExecutor;
62  
63  	private ExecutorManager shutdownExecutor;
64  
65  	private Logger internalLogger;
66  
67  	private AtomicBoolean initialized;
68  
69  	private AtomicBoolean waitingBootstrap;
70  
71  	private Thread shutdownHook = new Thread(new Runnable() {
72  		public void run() {
73  			internalLogger = new InternalLogger();
74  			shutdownExecutor.executeAll(commandsBeforeShutdown);
75  			shutdownExecutor.orderProperShutdown();
76  			shutdownExecutor.awaitTermination(TERMINATION_TIMEOUT);
77  			boolean terminatedAllTasks = ExecutorManagerFactory.doProperExecutorManagersShutdown();
78  			if (!terminatedAllTasks) {
79  				try {
80  					terminatedAllTasks = ExecutorManagerFactory
81  							.awaitExecutorManagersShutdown(TERMINATION_TIMEOUT);
82  				} catch (TerminationException e) {
83  					e.printStackTrace(System.err);
84  				}
85  				if (!terminatedAllTasks) {
86  					// FIXME: What should we do? wait forever? or just drop the tasks?
87  				}
88  			}
89  			backgroundExecutor.orderProperShutdown();
90  			backgroundExecutor.awaitTermination(TERMINATION_TIMEOUT);
91  		}
92  	});
93  
94  	private MonitorableTask finalizeBootstrap = new MonitorableTask(new Runnable() {
95  		public void run() {
96  			try {
97  				submitBackgroundTask(new Runnable() {
98  					public void run() {
99  						internalLogger = LoggerFactory.getLogger("net.sourceforge.acelogger");
100 						initialized.set(true);
101 					}
102 				});
103 			} catch (Exception e) {
104 				// FIXME: Should we do this? If there's an exception the framework is compromised by now
105 				shutdownHook.start();
106 			}
107 		}
108 	});
109 
110 	private Runnable setup = new NotifiableTask(new Runnable() {
111 		public void run() {
112 			LoggerFactory.registerLogger(internalLogger);
113 			internalLogger.info("LogControlle.setupComplete");
114 		}
115 	}, finalizeBootstrap);
116 
117 	private LogController() {
118 		internalLogger = new InternalLogger();
119 		Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionLogger.getInstance());
120 		Runtime.getRuntime().addShutdownHook(shutdownHook);
121 		backgroundExecutor = new QueuedExecutorManager("background");
122 		shutdownExecutor = new PooledExecutorManager("commandsBeforeShutdown", DEFAULT_POOL_SIZE);
123 		commandsBeforeShutdown = new ArrayList<Runnable>();
124 		initialized = new AtomicBoolean(false);
125 		waitingBootstrap = new AtomicBoolean(true);
126 		backgroundExecutor.execute(setup);
127 	}
128 
129 	public static void submitBackgroundTask(Runnable command) {
130 		INSTANCE.backgroundExecutor.execute(command);
131 	}
132 
133 	public static void submitBackgroundTask(final Runnable command, final ExecutorManager executor) {
134 		final Runnable process = new Runnable() {
135 			public void run() {
136 				executor.execute(command);
137 			}
138 		};
139 		submitBackgroundTask(process);
140 	}
141 
142 	public static void submitShutdownTask(Runnable command) {
143 		INSTANCE.commandsBeforeShutdown.add(command);
144 	}
145 
146 	public static void submitShutdownTask(final Runnable command, final ExecutorManager executor) {
147 		final Runnable process = new Runnable() {
148 			public void run() {
149 				executor.execute(command);
150 			}
151 		};
152 		submitShutdownTask(process);
153 	}
154 
155 	public static void ensureInitialization() {
156 		if (!INSTANCE.initialized.get() && INSTANCE.waitingBootstrap.get()) {
157 			try {
158 				if (INSTANCE.waitingBootstrap.compareAndSet(true, false)) {
159 					INSTANCE.finalizeBootstrap.awaitTermination(SETUP_TIMEOUT);
160 				}
161 			} catch (final InterruptedException e) {
162 				INSTANCE.internalLogger.fatal("Could not initialize after {0} ms", SETUP_TIMEOUT);
163 			}
164 		}
165 	}
166 
167 	public static Logger getInternalLogger() {
168 		return INSTANCE.internalLogger;
169 	}
170 
171 }