package org.sef4j.core.api.logger;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.sef4j.core.api.EventSender;
import org.sef4j.core.api.logger.EventLoggerContext.EventLoggerContextListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* similar to slf4j org.slf4j.LoggerFactory, but for event ...
*
* This class is a factory and the container manager for all created EventLogger elements.
* This class uses EventLoggerContext to determine which EventSenders to attach to EventLoggers.
* The EventContext may be changed at runtime for a EventLoggerFactory
*
* it is preferable to use this class and EventLogger injected by an IOC container
* ... But you can also use default static instance, store in static singleton EventLoggerFactoryStaticBinder
*
*/
public class EventLoggerFactory {
private static final Logger LOG = LoggerFactory.getLogger(EventLoggerFactory.class);
@SuppressWarnings("unchecked")
private static final EventSender<Object>[] EMPTY_EVENT_SENDER_ARRAY = (EventSender<Object>[]) new EventSender<?>[0];
private EventLoggerContext eventLoggerContext;
private Object lock = new Object();
private Map<String,EventLogger> eventLoggers = new HashMap<String,EventLogger>();
private EventLoggerContextListener innerEventLoggerContextListener = new EventLoggerContextListener() {
@Override
public void onChangeInheritedLoggers(String eventLoggerName) {
onEventLoggerContext_ChangeInheritedLoggers(eventLoggerName);
}
};
// ------------------------------------------------------------------------
public EventLoggerFactory(EventLoggerContext eventLoggerContext) {
this.eventLoggerContext = eventLoggerContext;
this.eventLoggerContext.addContextListener(innerEventLoggerContextListener);
}
// API
// ------------------------------------------------------------------------
public EventLogger getEventLogger(String eventLoggerName) {
EventLogger res;
synchronized(lock) {
res = eventLoggers.get(eventLoggerName);
}
if (res == null) {
EventSender<Object>[] inheritedAppenders = safeGetInheritedAppenderFor(eventLoggerName);
synchronized(lock) {
res = eventLoggers.get(eventLoggerName);
if (res == null) {
res = new EventLogger(this, eventLoggerName, inheritedAppenders);
eventLoggers.put(eventLoggerName, res);
}
}
}
return res;
}
// SPI
// ------------------------------------------------------------------------
public void resetContext(EventLoggerContext newContext) {
if (newContext == null) throw new IllegalArgumentException();
LOG.info("EventLoggerFactory.resetContext() ...");
synchronized(lock) {
// unconfigure from previous context
if (this.eventLoggerContext != null) {
doCleanupForEventContext();
}
// do set singleton context
this.eventLoggerContext = newContext;
// reconfigure for new context
doInitializeForEventContext();
}// end synchronized
LOG.info("... done EventLoggerFactory.resetContext()");
}
// internal
// ------------------------------------------------------------------------
private void doInitializeForEventContext() {
// => recompute, attach all appenders on all already created eventLoggers
if (!eventLoggers.isEmpty()) {
LOG.info("attach appenders for " + eventLoggers.size() + " existing eventLogger(s)");
doReconfigureAppenderForLoggers(eventLoggers);
}
this.eventLoggerContext.addContextListener(innerEventLoggerContextListener);
}
private void doCleanupForEventContext() {
this.eventLoggerContext.removeContextListener(innerEventLoggerContextListener);
if (!eventLoggers.isEmpty()) {
LOG.info("detach appenders for " + eventLoggers.size() + " existing eventLogger(s)");
// => detach all appenders on all eventLoggers
for(EventLogger eventLogger : eventLoggers.values()) {
eventLogger.configureInheritedAppenders(EMPTY_EVENT_SENDER_ARRAY);
}
}
}
protected EventSender<Object>[] safeGetInheritedAppenderFor(String eventLoggerName) {
EventSender<Object>[] inheritedAppenders;
try {
inheritedAppenders = eventLoggerContext.getInheritedAppendersFor(eventLoggerName);
} catch(Exception ex) {
inheritedAppenders = EMPTY_EVENT_SENDER_ARRAY;
LOG.error("Failed to compute inherited appenders for " + eventLoggerName + "! .. use empty, no rethrow ex", ex);
// ignore, no rethrow!
}
return inheritedAppenders;
}
protected Map<String,EventSender<Object>[]> safeGetInheritedAppenderFor(Set<String> eventLoggerNames) {
Map<String,EventSender<Object>[]> res;
try {
res = eventLoggerContext.getInheritedAppendersFor(eventLoggerNames);
} catch(Exception ex) {
// should not occurs... but fallback to safe loop
res = new HashMap<String,EventSender<Object>[]>();
for(String eventLoggerName : eventLoggerNames) {
res.put(eventLoggerName, safeGetInheritedAppenderFor(eventLoggerName));
}
}
return res;
}
protected void onEventLoggerContext_ChangeInheritedLoggers(String parentEventLoggerName) {
synchronized(lock) {
// collect descendant loggerNames
Map<String,EventLogger> descendantLoggers = new HashMap<String,EventLogger>();
for(EventLogger eventLogger : eventLoggers.values()) {
String name = eventLogger.getEventLoggerName();
if (name.startsWith(parentEventLoggerName)
&& (name.length() == parentEventLoggerName.length()
|| name.charAt(parentEventLoggerName.length()) == '.')) {
// matching descendant
descendantLoggers.put(name, eventLogger);
}
}
// reconfigure descendant loggers
doReconfigureAppenderForLoggers(descendantLoggers);
}
}
private void doReconfigureAppenderForLoggers(Map<String,EventLogger> loggers) {
Map<String,EventSender<Object>[]> appendersPerLogger = safeGetInheritedAppenderFor(loggers.keySet());
for(EventLogger eventLogger : loggers.values()) {
String eventLoggerName = eventLogger.getEventLoggerName();
EventSender<Object>[] appenders = appendersPerLogger.get(eventLoggerName);
if (appenders == null) {
// should not occur
appenders = safeGetInheritedAppenderFor(eventLoggerName);
}
eventLogger.configureInheritedAppenders(appenders);
}
}
}