]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java
Remove unused login entry point
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / kernel / NodeLogger.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.cms.internal.kernel;
17
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.Iterator;
22 import java.util.LinkedList;
23 import java.util.List;
24 import java.util.ListIterator;
25 import java.util.Map;
26 import java.util.Properties;
27 import java.util.concurrent.BlockingQueue;
28 import java.util.concurrent.LinkedBlockingQueue;
29
30 import org.apache.log4j.AppenderSkeleton;
31 import org.apache.log4j.Level;
32 import org.apache.log4j.LogManager;
33 import org.apache.log4j.Logger;
34 import org.apache.log4j.PropertyConfigurator;
35 import org.apache.log4j.spi.LoggingEvent;
36 import org.argeo.ArgeoException;
37 import org.argeo.ArgeoLogListener;
38 import org.argeo.ArgeoLogger;
39 import org.argeo.cms.auth.CurrentUser;
40
41 /** Not meant to be used directly in standard log4j config */
42 class NodeLogger implements ArgeoLogger {
43
44 private Boolean disabled = false;
45
46 private String level = null;
47
48 private Level log4jLevel = null;
49 // private Layout layout;
50
51 private Properties configuration;
52
53 private AppenderImpl appender;
54
55 private final List<ArgeoLogListener> everythingListeners = Collections
56 .synchronizedList(new ArrayList<ArgeoLogListener>());
57 private final List<ArgeoLogListener> allUsersListeners = Collections
58 .synchronizedList(new ArrayList<ArgeoLogListener>());
59 private final Map<String, List<ArgeoLogListener>> userListeners = Collections
60 .synchronizedMap(new HashMap<String, List<ArgeoLogListener>>());
61
62 private BlockingQueue<LogEvent> events;
63 private LogDispatcherThread logDispatcherThread = new LogDispatcherThread();
64
65 private Integer maxLastEventsCount = 10 * 1000;
66
67 /** Marker to prevent stack overflow */
68 private ThreadLocal<Boolean> dispatching = new ThreadLocal<Boolean>() {
69
70 @Override
71 protected Boolean initialValue() {
72 return false;
73 }
74 };
75
76 public void init() {
77 try {
78 events = new LinkedBlockingQueue<LogEvent>();
79
80 // if (layout != null)
81 // setLayout(layout);
82 // else
83 // setLayout(new PatternLayout(pattern));
84 appender = new AppenderImpl();
85 reloadConfiguration();
86 Logger.getRootLogger().addAppender(appender);
87
88 logDispatcherThread = new LogDispatcherThread();
89 logDispatcherThread.start();
90 } catch (Exception e) {
91 throw new ArgeoException("Cannot initialize log4j");
92 }
93 }
94
95 public void destroy() throws Exception {
96 Logger.getRootLogger().removeAppender(appender);
97 allUsersListeners.clear();
98 for (List<ArgeoLogListener> lst : userListeners.values())
99 lst.clear();
100 userListeners.clear();
101
102 events.clear();
103 events = null;
104 logDispatcherThread.interrupt();
105 }
106
107 // public void setLayout(Layout layout) {
108 // this.layout = layout;
109 // }
110
111 public synchronized void register(ArgeoLogListener listener,
112 Integer numberOfPreviousEvents) {
113 String username = CurrentUser.getUsername();
114 if (username == null)
115 throw new ArgeoException(
116 "Only authenticated users can register a log listener");
117
118 if (!userListeners.containsKey(username)) {
119 List<ArgeoLogListener> lst = Collections
120 .synchronizedList(new ArrayList<ArgeoLogListener>());
121 userListeners.put(username, lst);
122 }
123 userListeners.get(username).add(listener);
124 List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(username,
125 numberOfPreviousEvents);
126 for (LogEvent evt : lastEvents)
127 dispatchEvent(listener, evt);
128 }
129
130 public synchronized void registerForAll(ArgeoLogListener listener,
131 Integer numberOfPreviousEvents, boolean everything) {
132 if (everything)
133 everythingListeners.add(listener);
134 else
135 allUsersListeners.add(listener);
136 List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(null,
137 numberOfPreviousEvents);
138 for (LogEvent evt : lastEvents)
139 if (everything || evt.getUsername() != null)
140 dispatchEvent(listener, evt);
141 }
142
143 public synchronized void unregister(ArgeoLogListener listener) {
144 String username = CurrentUser.getUsername();
145 if (username == null)// FIXME
146 return;
147 if (!userListeners.containsKey(username))
148 throw new ArgeoException("No user listeners " + listener
149 + " registered for user " + username);
150 if (!userListeners.get(username).contains(listener))
151 throw new ArgeoException("No user listeners " + listener
152 + " registered for user " + username);
153 userListeners.get(username).remove(listener);
154 if (userListeners.get(username).isEmpty())
155 userListeners.remove(username);
156
157 }
158
159 public synchronized void unregisterForAll(ArgeoLogListener listener) {
160 everythingListeners.remove(listener);
161 allUsersListeners.remove(listener);
162 }
163
164 /** For development purpose, since using regular logging is not easy here */
165 static void stdOut(Object obj) {
166 System.out.println(obj);
167 }
168
169 // public void setPattern(String pattern) {
170 // this.pattern = pattern;
171 // }
172
173 public void setDisabled(Boolean disabled) {
174 this.disabled = disabled;
175 }
176
177 public void setLevel(String level) {
178 this.level = level;
179 }
180
181 public void setConfiguration(Properties configuration) {
182 this.configuration = configuration;
183 }
184
185 public void updateConfiguration(Properties configuration) {
186 setConfiguration(configuration);
187 reloadConfiguration();
188 }
189
190 public Properties getConfiguration() {
191 return configuration;
192 }
193
194 /** Reloads configuration (if the configuration {@link Properties} is set) */
195 protected void reloadConfiguration() {
196 if (configuration != null) {
197 LogManager.resetConfiguration();
198 PropertyConfigurator.configure(configuration);
199 }
200 }
201
202 protected synchronized void processLoggingEvent(LogEvent event) {
203 if (disabled)
204 return;
205
206 if (dispatching.get())
207 return;
208
209 if (level != null && !level.trim().equals("")) {
210 if (log4jLevel == null || !log4jLevel.toString().equals(level))
211 try {
212 log4jLevel = Level.toLevel(level);
213 } catch (Exception e) {
214 System.err
215 .println("Log4j level could not be set for level '"
216 + level + "', resetting it to null.");
217 e.printStackTrace();
218 level = null;
219 }
220
221 if (log4jLevel != null
222 && !event.getLoggingEvent().getLevel()
223 .isGreaterOrEqual(log4jLevel)) {
224 return;
225 }
226 }
227
228 try {
229 // admin listeners
230 Iterator<ArgeoLogListener> everythingIt = everythingListeners
231 .iterator();
232 while (everythingIt.hasNext())
233 dispatchEvent(everythingIt.next(), event);
234
235 if (event.getUsername() != null) {
236 Iterator<ArgeoLogListener> allUsersIt = allUsersListeners
237 .iterator();
238 while (allUsersIt.hasNext())
239 dispatchEvent(allUsersIt.next(), event);
240
241 if (userListeners.containsKey(event.getUsername())) {
242 Iterator<ArgeoLogListener> userIt = userListeners.get(
243 event.getUsername()).iterator();
244 while (userIt.hasNext())
245 dispatchEvent(userIt.next(), event);
246 }
247 }
248 } catch (Exception e) {
249 stdOut("Cannot process logging event");
250 e.printStackTrace();
251 }
252 }
253
254 protected void dispatchEvent(ArgeoLogListener logListener, LogEvent evt) {
255 LoggingEvent event = evt.getLoggingEvent();
256 logListener.appendLog(evt.getUsername(), event.getTimeStamp(), event
257 .getLevel().toString(), event.getLoggerName(), event
258 .getThreadName(), event.getMessage(), event
259 .getThrowableStrRep());
260 }
261
262 private class AppenderImpl extends AppenderSkeleton {
263 public boolean requiresLayout() {
264 return false;
265 }
266
267 public void close() {
268 }
269
270 @Override
271 protected void append(LoggingEvent event) {
272 if (events != null) {
273 try {
274 String username = CurrentUser.getUsername();
275 events.put(new LogEvent(username, event));
276 } catch (InterruptedException e) {
277 // silent
278 }
279 }
280 }
281
282 }
283
284 private class LogDispatcherThread extends Thread {
285 /** encapsulated in order to simplify concurrency management */
286 private LinkedList<LogEvent> lastEvents = new LinkedList<LogEvent>();
287
288 public LogDispatcherThread() {
289 super("Argeo Logging Dispatcher Thread");
290 }
291
292 public void run() {
293 while (events != null) {
294 try {
295 LogEvent loggingEvent = events.take();
296 processLoggingEvent(loggingEvent);
297 addLastEvent(loggingEvent);
298 } catch (InterruptedException e) {
299 if (events == null)
300 return;
301 }
302 }
303 }
304
305 protected synchronized void addLastEvent(LogEvent loggingEvent) {
306 if (lastEvents.size() >= maxLastEventsCount)
307 lastEvents.poll();
308 lastEvents.add(loggingEvent);
309 }
310
311 public synchronized List<LogEvent> getLastEvents(String username,
312 Integer maxCount) {
313 LinkedList<LogEvent> evts = new LinkedList<LogEvent>();
314 ListIterator<LogEvent> it = lastEvents.listIterator(lastEvents
315 .size());
316 int count = 0;
317 while (it.hasPrevious() && (count < maxCount)) {
318 LogEvent evt = it.previous();
319 if (username == null || username.equals(evt.getUsername())) {
320 evts.push(evt);
321 count++;
322 }
323 }
324 return evts;
325 }
326 }
327
328 private class LogEvent {
329 private final String username;
330 private final LoggingEvent loggingEvent;
331
332 public LogEvent(String username, LoggingEvent loggingEvent) {
333 super();
334 this.username = username;
335 this.loggingEvent = loggingEvent;
336 }
337
338 @Override
339 public int hashCode() {
340 return loggingEvent.hashCode();
341 }
342
343 @Override
344 public boolean equals(Object obj) {
345 return loggingEvent.equals(obj);
346 }
347
348 @Override
349 public String toString() {
350 return username + "@ " + loggingEvent.toString();
351 }
352
353 public String getUsername() {
354 return username;
355 }
356
357 public LoggingEvent getLoggingEvent() {
358 return loggingEvent;
359 }
360
361 }
362 }