/* * Copyright 2010 NCHOVY * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.log.api.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.felix.ipojo.annotations.Component; import org.apache.felix.ipojo.annotations.Invalidate; import org.apache.felix.ipojo.annotations.Provides; import org.apache.felix.ipojo.annotations.Validate; import org.krakenapps.log.api.Log; import org.krakenapps.log.api.LogPipe; import org.krakenapps.log.api.Logger; import org.krakenapps.log.api.LoggerFactory; import org.krakenapps.log.api.LoggerFactoryEventListener; import org.krakenapps.log.api.LoggerFactoryRegistryEventListener; import org.krakenapps.log.api.LoggerRegistry; import org.krakenapps.log.api.LoggerRegistryEventListener; @Component(name = "logger-registry") @Provides(specifications = { LoggerRegistry.class }) public class LoggerRegistryImpl implements LoggerRegistry, LoggerFactoryRegistryEventListener, LoggerFactoryEventListener, LogPipe { private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerRegistryImpl.class.getName()); private ConcurrentMap<String, Logger> loggers; private Set<LoggerRegistryEventListener> callbacks; private ConcurrentMap<String, Set<LogPipe>> pipeMap; private boolean isOpen = false; public LoggerRegistryImpl() { loggers = new ConcurrentHashMap<String, Logger>(); callbacks = Collections.newSetFromMap(new ConcurrentHashMap<LoggerRegistryEventListener, Boolean>()); pipeMap = new ConcurrentHashMap<String, Set<LogPipe>>(); } @Override public boolean isOpen() { return isOpen; } @Validate public void start() { callbacks.clear(); isOpen = true; } @Invalidate public void stop() { isOpen = false; callbacks.clear(); } @Override public void factoryAdded(LoggerFactory loggerFactory) { loggerFactory.addListener(this); } @Override public void factoryRemoved(LoggerFactory loggerFactory) { loggerFactory.removeListener(this); // remove all related loggers List<Logger> removeList = new ArrayList<Logger>(); for (Logger logger : loggers.values()) if (logger.getFactoryFullName().equals(loggerFactory.getFullName())) removeList.add(logger); for (Logger logger : removeList) { try { // logger stop event caused by factory removal will not be sent. logger.clearEventListeners(); logger.stop(); removeLogger(logger); } catch (Exception e) { log.warn("kraken-log-api: logger remove error", e); } } } @Override public Collection<Logger> getLoggers() { return new ArrayList<Logger>(loggers.values()); } @Override public Logger getLogger(String fullName) { return loggers.get(fullName); } @Override public Logger getLogger(String namespace, String name) { return loggers.get(namespace + "\\" + name); } @Override public void addLogger(Logger logger) { log.debug("kraken log api: adding logger [{}]", logger.getFullName()); Logger old = loggers.putIfAbsent(logger.getFullName(), logger); if (old != null) throw new IllegalStateException("logger already exists: " + logger.getFullName()); // connect pipe logger.addLogPipe(this); log.debug("kraken log api: logger [{}] added", logger.getFullName()); // invoke logger event callbacks for (LoggerRegistryEventListener callback : callbacks) { try { callback.loggerAdded(logger); } catch (Exception e) { log.warn("kraken-log-api: logger registry callback should not throw exception", e); } } } @Override public void removeLogger(Logger logger) { if (logger == null) throw new IllegalArgumentException("logger must not be null"); log.debug("kraken log api: removing logger [{}]", logger.getFullName()); if (logger.isRunning()) throw new IllegalStateException("logger is still running"); loggers.remove(logger.getFullName()); // disconnect pipe logger.removeLogPipe(this); log.debug("kraken log api: logger [{}] removed", logger.getFullName()); // invoke logger event callbacks for (LoggerRegistryEventListener callback : callbacks) { try { callback.loggerRemoved(logger); } catch (Exception e) { log.warn("kraken-log-api: logger registry callback should not throw exception", e); } } } @Override public void loggerCreated(LoggerFactory factory, Logger logger, Properties config) { addLogger(logger); } @Override public void loggerDeleted(LoggerFactory factory, Logger logger) { if (logger != null) removeLogger(logger); } @Override public void addLogPipe(String loggerFactoryName, LogPipe pipe) { Set<LogPipe> pipes = Collections.newSetFromMap(new ConcurrentHashMap<LogPipe, Boolean>()); Set<LogPipe> oldPipes = pipeMap.putIfAbsent(loggerFactoryName, pipes); if (oldPipes != null) pipes = oldPipes; pipes.add(pipe); } @Override public void removeLogPipe(String loggerFactoryName, LogPipe pipe) { Set<LogPipe> pipes = pipeMap.get(loggerFactoryName); if (pipes == null) return; pipes.remove(pipe); } @Override public void addListener(LoggerRegistryEventListener callback) { if (callback == null) throw new IllegalArgumentException("callback must not be null"); callbacks.add(callback); } @Override public void removeListener(LoggerRegistryEventListener callback) { if (callback == null) throw new IllegalArgumentException("callback must not be null"); callbacks.remove(callback); } @Override public void onLog(Logger logger, Log log) { Set<LogPipe> pipes = pipeMap.get(logger.getFactoryName()); if (pipes == null) return; for (LogPipe pipe : pipes) { pipe.onLog(logger, log); } } }