Inital code drop of logback-config. 79/1679/2
authorTomas Olvecky <tolvecky@cisco.com>
Fri, 4 Oct 2013 14:29:41 +0000 (16:29 +0200)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 7 Oct 2013 13:39:07 +0000 (13:39 +0000)
This module bridges logback configuration over config-subsystem, allowing to reconfigure logback via JMX.

Change-Id: I52644b628d384d8ca015885cc9f016f4429238d4
Signed-off-by: Tomas Olvecky <tolvecky@cisco.com>
13 files changed:
opendaylight/config/logback-config/pom.xml [new file with mode: 0644]
opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetter.java [new file with mode: 0644]
opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImpl.java [new file with mode: 0644]
opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModule.java [new file with mode: 0644]
opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java [new file with mode: 0644]
opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackStatusListener.java [new file with mode: 0644]
opendaylight/config/logback-config/src/main/yang/config-logging.yang [new file with mode: 0644]
opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImplTest.java [new file with mode: 0644]
opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java [new file with mode: 0644]
opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java [new file with mode: 0644]
opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java [new file with mode: 0644]
opendaylight/config/logback-config/src/test/resources/simple_config_logback.xml [new file with mode: 0644]
opendaylight/config/pom.xml

diff --git a/opendaylight/config/logback-config/pom.xml b/opendaylight/config/logback-config/pom.xml
new file mode 100644 (file)
index 0000000..6b79e7c
--- /dev/null
@@ -0,0 +1,121 @@
+<?xml version="1.0"?>
+<project
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+        xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>config-subsystem</artifactId>
+        <version>0.2.1-SNAPSHOT</version>
+    </parent>
+    <artifactId>logback-config</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+    <prerequisites>
+        <maven>3.0.4</maven>
+    </prerequisites>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>config-api</artifactId>
+            <version>0.2.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.bgpcep</groupId>
+            <artifactId>concepts</artifactId>
+            <version>0.2.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>${logback.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <version>${logback.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>config-manager</artifactId>
+            <version>0.2.1-SNAPSHOT</version>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>config-manager</artifactId>
+            <version>0.2.1-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>config-util</artifactId>
+            <version>0.2.1-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.bgpcep</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <version>0.2.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Private-Package>
+                        </Private-Package>
+                        <Import-Package>
+                            ch.qos.logback.classic,
+                            ch.qos.logback.classic.encoder,
+                            ch.qos.logback.classic.filter,
+                            ch.qos.logback.classic.spi,
+                            ch.qos.logback.core,
+                            ch.qos.logback.core.status,
+                            ch.qos.logback.core.encoder,
+                            ch.qos.logback.core.rolling,
+                            org.opendaylight.protocol.concepts,
+                            org.opendaylight.controller.config.api,
+                            org.opendaylight.controller.config.api.runtime,
+                            org.opendaylight.controller.config.api.annotations,
+                            org.opendaylight.controller.config.spi,
+                            com.google.common.base,
+                            com.google.common.collect,
+                            org.apache.commons.lang3,
+                            org.slf4j
+                        </Import-Package>
+                        <Export-Package>
+                            org.opendaylight.controller.config.yang.logback.config,
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetter.java b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetter.java
new file mode 100644 (file)
index 0000000..3241fb0
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+ * Generated file
+
+ * Generated from: yang module name: config-test  yang module local name: testing
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Fri Sep 27 14:06:33 CEST 2013
+ *
+ * Do not modify this file unless it is present under src/main directory
+ */
+package org.opendaylight.controller.config.yang.logback.config;
+
+/**
+ * Updates current state of Logback configuration.
+ */
+public interface ContextSetter {
+
+    public void updateContext(LogbackModule module);
+
+}
diff --git a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImpl.java b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImpl.java
new file mode 100644 (file)
index 0000000..7e4095f
--- /dev/null
@@ -0,0 +1,221 @@
+/**
+ * Generated file
+
+ * Generated from: yang module name: config-test  yang module local name: testing
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Fri Sep 27 14:06:33 CEST 2013
+ *
+ * Do not modify this file unless it is present under src/main directory
+ */
+package org.opendaylight.controller.config.yang.logback.config;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.*;
+
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.filter.ThresholdFilter;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
+import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+
+/**
+ * Implementation of {@link ContextSetter}. Resets running logback
+ * configuration.
+ */
+public class ContextSetterImpl implements ContextSetter, Closeable {
+
+    private final LogbackStatusListener statusListener;
+    private static final org.slf4j.Logger classLogger = LoggerFactory
+            .getLogger(ContextSetterImpl.class);
+
+    public ContextSetterImpl(
+            LogbackRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) {
+        statusListener = new LogbackStatusListener(
+                rootRuntimeBeanRegistratorWrapper);
+        statusListener.register();
+    }
+
+    public void updateContext(LogbackModule module) {
+        LoggerContext context = (LoggerContext) LoggerFactory
+                .getILoggerFactory();
+
+        List<ch.qos.logback.classic.Logger> loggersBefore = context
+                .getLoggerList();
+
+        createLoggers(context, module, Sets.newHashSet(loggersBefore));
+    }
+
+    private Map<String, Appender<ILoggingEvent>> createConsoleAppenders(
+            LoggerContext context, LogbackModule module) {
+        Map<String, Appender<ILoggingEvent>> appendersMap = new HashMap<>();
+        for (ConsoleAppenderTO appender : module.getConsoleAppenderTO()) {
+            Preconditions.checkState(
+                    appendersMap.containsKey(appender.getName()) == false,
+                    "Duplicate appender name %s", appender.getName());
+            ch.qos.logback.core.ConsoleAppender app = new ch.qos.logback.core.ConsoleAppender();
+            app.setContext(context);
+            PatternLayoutEncoder encoder = new PatternLayoutEncoder();
+            encoder.setContext(context);
+            encoder.setPattern(appender.getEncoderPattern());
+            encoder.start();
+            app.setEncoder(encoder);
+            ThresholdFilter filter = new ThresholdFilter();
+            filter.setContext(context);
+            filter.setLevel(appender.getThresholdFilter());
+            filter.start();
+            app.getCopyOfAttachedFiltersList().add(filter);
+            app.setName(appender.getName());
+            app.start();
+            appendersMap.put(app.getName(), app);
+        }
+        return appendersMap;
+    }
+
+    private void createLoggers(LoggerContext context, LogbackModule module,
+            Set<ch.qos.logback.classic.Logger> loggersBefore) {
+
+        Map<String, Appender<ILoggingEvent>> appendersMap = getAppenders(
+                module, context);
+
+        for (LoggerTO logger : module.getLoggerTO()) {
+            classLogger.trace("Setting configuration for logger {}",
+                    logger.getLoggerName());
+            final ch.qos.logback.classic.Logger logbackLogger = context
+                    .getLogger(logger.getLoggerName());
+
+            Optional<Set<Appender<ILoggingEvent>>> appendersBefore = getAppendersBefore(
+                    loggersBefore, logbackLogger);
+            classLogger.trace("Logger {}: Appenders registered before: {}",
+                    logger.getLoggerName(),
+                    appendersBefore.isPresent() ? appendersBefore.get()
+                            : "NO APPENDERS BEFORE");
+
+            logbackLogger.setLevel(Level.toLevel(logger.getLevel()));
+
+            addNewAppenders(appendersMap, logger, logbackLogger,
+                    appendersBefore);
+            removeBeforeAppenders(loggersBefore, logger, logbackLogger,
+                    appendersBefore);
+        }
+    }
+
+    private void addNewAppenders(
+            Map<String, Appender<ILoggingEvent>> appendersMap, LoggerTO logger,
+            ch.qos.logback.classic.Logger logbackLogger,
+            Optional<Set<Appender<ILoggingEvent>>> appendersBefore) {
+        for (String appenderName : logger.getAppenders()) {
+            if (appendersMap.containsKey(appenderName)) {
+                logbackLogger.addAppender(appendersMap.get(appenderName));
+                classLogger.trace("Logger {}: Adding new appender: {}",
+                        logger.getLoggerName(), appenderName);
+            } else {
+                throw new IllegalStateException(
+                        "No appender "
+                                + appenderName
+                                + " found. This error should have been discovered by validation");
+            }
+        }
+    }
+
+    private void removeBeforeAppenders(
+            Set<ch.qos.logback.classic.Logger> loggersBefore, LoggerTO logger,
+            ch.qos.logback.classic.Logger logbackLogger,
+            Optional<Set<Appender<ILoggingEvent>>> appendersBefore) {
+        if (appendersBefore.isPresent()) {
+            for (Appender<ILoggingEvent> appenderBefore : appendersBefore.get()) {
+                logbackLogger.detachAppender(appenderBefore);
+                appenderBefore.stop();
+                classLogger.trace("Logger {}: Removing old appender: {}",
+                        logger.getLoggerName(), appenderBefore.getName());
+            }
+            loggersBefore.remove(logbackLogger);
+        }
+    }
+
+    private Optional<Set<Appender<ILoggingEvent>>> getAppendersBefore(
+            Set<ch.qos.logback.classic.Logger> loggersBefore,
+            ch.qos.logback.classic.Logger logbackLogger) {
+        if (loggersBefore.contains(logbackLogger)) {
+            Iterator<Appender<ILoggingEvent>> appenderIt = logbackLogger
+                    .iteratorForAppenders();
+            Set<Appender<ILoggingEvent>> appendersBefore = Sets.newHashSet();
+            while (appenderIt.hasNext()) {
+                appendersBefore.add(appenderIt.next());
+            }
+            return Optional.of(appendersBefore);
+        } else
+            return Optional.absent();
+
+    }
+
+    private Map<String, Appender<ILoggingEvent>> getAppenders(
+            LogbackModule module, LoggerContext context) {
+        Map<String, Appender<ILoggingEvent>> appendersMap = new HashMap<>();
+        addAllAppenders(appendersMap, createRollingAppenders(context, module));
+        addAllAppenders(appendersMap, createConsoleAppenders(context, module));
+
+        return appendersMap;
+    }
+
+    private void addAllAppenders(
+            Map<String, Appender<ILoggingEvent>> allAppenders,
+            Map<String, Appender<ILoggingEvent>> appendersToAdd) {
+        for (String appenderName : appendersToAdd.keySet()) {
+            Preconditions.checkState(
+                    allAppenders.containsKey(appenderName) == false,
+                    "Duplicate appender name %s", appenderName);
+            allAppenders.put(appenderName, appendersToAdd.get(appenderName));
+        }
+    }
+
+    private Map<String, Appender<ILoggingEvent>> createRollingAppenders(
+            LoggerContext context, LogbackModule module) {
+        Map<String, Appender<ILoggingEvent>> appendersMap = new HashMap<>();
+        for (RollingFileAppenderTO appender : module.getRollingFileAppenderTO()) {
+            Preconditions.checkState(
+                    appendersMap.containsKey(appender.getName()) == false,
+                    "Duplicate appender name %s", appender.getName());
+            ch.qos.logback.core.rolling.RollingFileAppender app = new ch.qos.logback.core.rolling.RollingFileAppender<>();
+            app.setAppend(appender.getAppend());
+            app.setContext(context);
+            PatternLayoutEncoder encoder = new PatternLayoutEncoder();
+            encoder.setContext(context);
+            encoder.setPattern(appender.getEncoderPattern());
+            encoder.start();
+            app.setEncoder(encoder);
+            app.setFile(appender.getFileName());
+            FixedWindowRollingPolicy policy = new FixedWindowRollingPolicy();
+            policy.setContext(context);
+            policy.setMaxIndex(appender.getMaxIndex());
+            policy.setMinIndex(appender.getMinIndex());
+            policy.setFileNamePattern(appender.getFileNamePattern());
+            policy.setParent(app);
+            policy.start();
+            app.setRollingPolicy(policy);
+            SizeBasedTriggeringPolicy triggeringPolicy = new SizeBasedTriggeringPolicy();
+            triggeringPolicy.setContext(context);
+            triggeringPolicy.setMaxFileSize(appender.getMaxFileSize());
+            triggeringPolicy.start();
+            app.setTriggeringPolicy(triggeringPolicy);
+            app.setName(appender.getName());
+            app.start();
+            appendersMap.put(app.getName(), app);
+        }
+        return appendersMap;
+    }
+
+    @Override
+    public void close() throws IOException {
+        statusListener.close();
+    }
+}
diff --git a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModule.java b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModule.java
new file mode 100644 (file)
index 0000000..9b5cbfc
--- /dev/null
@@ -0,0 +1,152 @@
+/**
+ * Generated file
+
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Wed Jul 17 15:26:45 CEST 2013
+ *
+ * Do not modifiy this file unless it is present under src/main directory
+ */
+package org.opendaylight.controller.config.yang.logback.config;
+
+import java.util.Set;
+
+import org.opendaylight.controller.config.api.JmxAttribute;
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+
+import com.google.common.collect.Sets;
+
+/**
+*
+*/
+public final class LogbackModule
+        extends
+        org.opendaylight.controller.config.yang.logback.config.AbstractLogbackModule {
+
+    public LogbackModule(
+            org.opendaylight.controller.config.api.ModuleIdentifier name,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(name, dependencyResolver);
+    }
+
+    public LogbackModule(
+            org.opendaylight.controller.config.api.ModuleIdentifier name,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            org.opendaylight.controller.config.yang.logback.config.AbstractLogbackModule oldModule,
+            java.lang.AutoCloseable oldInstance) {
+        super(name, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void validate() {
+        super.validate();
+        Set<String> appenderNames = Sets.newHashSet();
+        validateRollingObjects(appenderNames);
+        validateConsoleObjects(appenderNames);
+        validateLoggersObjects(appenderNames);
+    }
+
+    private void validateLoggersObjects(Set<String> appenderNames) {
+        JmxAttributeValidationException.checkNotNull(getLoggerTO(),
+                loggersJmxAttribute);
+
+        for (LoggerTO loggerToValidate : getLoggerTO()) {
+            JmxAttributeValidationException.checkNotNull(
+                    loggerToValidate.getLoggerName(), "LoggerName is null",
+                    loggersJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(
+                    loggerToValidate.getLevel(), "Level is null",
+                    loggersJmxAttribute);
+            JmxAttributeValidationException.checkCondition(!loggerToValidate
+                    .getLoggerName().isEmpty(), "LoggerName needs to be set",
+                    loggersJmxAttribute);
+            JmxAttributeValidationException.checkCondition(!loggerToValidate
+                    .getLevel().isEmpty(), "Level needs to be set",
+                    loggersJmxAttribute);
+
+            for (String appenderName : loggerToValidate.getAppenders()) {
+                JmxAttributeValidationException
+                        .checkCondition(
+                                appenderNames.contains(appenderName),
+                                "Appender "
+                                        + appenderName
+                                        + " referenced by logger "
+                                        + loggerToValidate.getLoggerName()
+                                        + " not present in configuration, present appenders: "
+                                        + appenderNames, loggersJmxAttribute);
+            }
+
+        }
+    }
+
+    private void validateConsoleObjects(Set<String> appenderNames) {
+
+        JmxAttributeValidationException.checkNotNull(getConsoleAppenderTO(),
+                consoleAppendersJmxAttribute);
+        for (ConsoleAppenderTO object : getConsoleAppenderTO()) {
+            JmxAttributeValidationException.checkNotNull(
+                    object.getEncoderPattern(), "EncoderPattern is null",
+                    consoleAppendersJmxAttribute);
+
+            validateAppenderName(appenderNames, object.getName(),
+                    consoleAppendersJmxAttribute);
+
+            JmxAttributeValidationException.checkNotNull(
+                    object.getThresholdFilter(), "Filterlevel is null",
+                    consoleAppendersJmxAttribute);
+        }
+    }
+
+    private void validateRollingObjects(Set<String> appenderNames) {
+
+        JmxAttributeValidationException.checkNotNull(getRollingFileAppenderTO(),
+                rollingAppendersJmxAttribute);
+        for (RollingFileAppenderTO object : getRollingFileAppenderTO()) {
+            JmxAttributeValidationException.checkNotNull(
+                    object.getEncoderPattern(), "EncoderPattern is null",
+                    rollingAppendersJmxAttribute);
+
+            validateAppenderName(appenderNames, object.getName(),
+                    rollingAppendersJmxAttribute);
+
+            JmxAttributeValidationException.checkNotNull(object.getFileName(),
+                    "FileName is null", rollingAppendersJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(
+                    object.getMaxFileSize(), "MaxFileSize is null",
+                    rollingAppendersJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(object.getMinIndex(),
+                    "MinIndex is null", rollingAppendersJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(object.getMaxIndex(),
+                    "MaxIndex is null", rollingAppendersJmxAttribute);
+            JmxAttributeValidationException.checkCondition(!object
+                    .getEncoderPattern().isEmpty(),
+                    "EncoderPattern needs to be set",
+                    rollingAppendersJmxAttribute);
+            JmxAttributeValidationException.checkCondition(!object
+                    .getFileName().isEmpty(), "FileName needs to be set",
+                    rollingAppendersJmxAttribute);
+
+        }
+    }
+
+    private void validateAppenderName(Set<String> appenderNames,
+            String appenderName, JmxAttribute jmxAttribute) {
+        JmxAttributeValidationException.checkNotNull(appenderName,
+                "Name is null", jmxAttribute);
+        JmxAttributeValidationException.checkCondition(
+                appenderNames.contains(appenderName) == false,
+                "Duplicate appender name " + appenderName, jmxAttribute);
+        appenderNames.add(appenderName);
+        JmxAttributeValidationException.checkCondition(!appenderName.isEmpty(),
+                "Name needs to be set", jmxAttribute);
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        ContextSetterImpl setter = new ContextSetterImpl(
+                getRootRuntimeBeanRegistratorWrapper());
+
+        setter.updateContext(this);
+
+        return setter;
+    }
+}
diff --git a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java
new file mode 100644 (file)
index 0000000..eb0c7da
--- /dev/null
@@ -0,0 +1,213 @@
+/**
+ * Generated file
+
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Wed Jul 17 15:26:45 CEST 2013
+ *
+ * Do not modifiy this file unless it is present under src/main directory
+ */
+package org.opendaylight.controller.config.yang.logback.config;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.classic.spi.LoggerComparator;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
+import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+/**
+*
+*/
+public class LogbackModuleFactory
+        extends
+        org.opendaylight.controller.config.yang.logback.config.AbstractLogbackModuleFactory {
+
+    private static final String INSTANCE_NAME = "singleton";
+    private Map<String, LoggerTO> loggersDTOs;
+    private Map<String, RollingFileAppenderTO> rollingDTOs;
+    private Map<String, ConsoleAppenderTO> consoleDTOs;
+
+    @Override
+    public LogbackModule instantiateModule(String instanceName,
+            DependencyResolver dependencyResolver) {
+        Preconditions.checkArgument(instanceName.equals(INSTANCE_NAME),
+                "There should be just one instance of logback, named "
+                        + INSTANCE_NAME);
+        prepareDTOs();
+        LogbackModule module = new LogbackModule(new ModuleIdentifier(
+                getImplementationName(), INSTANCE_NAME), dependencyResolver);
+        module.setConsoleAppenderTO(Lists.newArrayList(consoleDTOs.values()));
+        module.setRollingFileAppenderTO(Lists.newArrayList(rollingDTOs.values()));
+        module.setLoggerTO(Lists.newArrayList(loggersDTOs.values()));
+        return module;
+    }
+
+    @Override
+    public LogbackModule instantiateModule(String instanceName,
+            DependencyResolver dependencyResolver, LogbackModule oldModule,
+            AutoCloseable oldInstance) {
+        Preconditions.checkArgument(instanceName.equals(INSTANCE_NAME),
+                "There should be just one instance of logback, named "
+                        + INSTANCE_NAME);
+        prepareDTOs();
+        LogbackModule module = new LogbackModule(new ModuleIdentifier(
+                getImplementationName(), INSTANCE_NAME), dependencyResolver,
+                oldModule, oldInstance);
+        module.setConsoleAppenderTO(Lists.newArrayList(consoleDTOs.values()));
+        /*
+         * module.setJCloudsAppender(Lists.newArrayList(jcloudsDTOs.values()));
+         */
+        module.setRollingFileAppenderTO(Lists.newArrayList(rollingDTOs.values()));
+        module.setLoggerTO(Lists.newArrayList(loggersDTOs.values()));
+        return module;
+    }
+
+    private void prepareDTOs() {
+        LoggerContext context = (LoggerContext) LoggerFactory
+                .getILoggerFactory();
+        this.loggersDTOs = prepareLoggersDTOs(context);
+        prepareAppendersDTOs(context);
+    }
+
+    private void prepareAppendersDTOs(LoggerContext context) {
+        this.rollingDTOs = new HashMap<>();
+        this.consoleDTOs = new HashMap<>();
+        ch.qos.logback.core.rolling.RollingFileAppender<ILoggingEvent> rollingApp;
+        ch.qos.logback.core.ConsoleAppender<ILoggingEvent> consoleApp;
+        Map<Logger, List<Appender<ILoggingEvent>>> appendersAll = new HashMap<>();
+        for (Logger log : context.getLoggerList()) {
+            List<Appender<ILoggingEvent>> appenders = new ArrayList<>();
+            Iterator<Appender<ILoggingEvent>> iter = log.iteratorForAppenders();
+            while (iter.hasNext()) {
+                Appender<ILoggingEvent> element = iter.next();
+                appenders.add(element);
+            }
+            appendersAll.put(log, appenders);
+        }
+        for (List<ch.qos.logback.core.Appender<ILoggingEvent>> appEntry : appendersAll.values()) {
+            for (ch.qos.logback.core.Appender<ILoggingEvent> appender : appEntry) {
+                if (appender instanceof ch.qos.logback.core.rolling.RollingFileAppender<?>) {
+                    RollingFileAppenderTO app = new RollingFileAppenderTO();
+                    rollingApp = (ch.qos.logback.core.rolling.RollingFileAppender< ILoggingEvent >) appender;
+                    app.setAppend(rollingApp.isAppend());
+                    PatternLayoutEncoder encoder = (PatternLayoutEncoder) rollingApp
+                            .getEncoder();
+                    app.setEncoderPattern(encoder.getPattern());
+                    app.setFileName(rollingApp.getFile());
+                    FixedWindowRollingPolicy rollingPolicy = (FixedWindowRollingPolicy) rollingApp
+                            .getRollingPolicy();
+                    app.setMaxIndex(rollingPolicy.getMaxIndex());
+                    app.setMinIndex(rollingPolicy.getMinIndex());
+                    SizeBasedTriggeringPolicy<ILoggingEvent> triggeringPolicy = (SizeBasedTriggeringPolicy<ILoggingEvent>) rollingApp
+                            .getTriggeringPolicy();
+                    app.setMaxFileSize(triggeringPolicy.getMaxFileSize());
+                    app.setFileNamePattern(rollingPolicy.getFileNamePattern());
+                    app.setName(rollingApp.getName());
+                    this.rollingDTOs.put(rollingApp.getName(), app);
+                }
+                if (appender instanceof ch.qos.logback.core.ConsoleAppender<?>) {
+                    ConsoleAppenderTO app = new ConsoleAppenderTO();
+                    consoleApp = (ch.qos.logback.core.ConsoleAppender<ILoggingEvent>) appender;
+                    consoleApp.getCopyOfAttachedFiltersList();
+                    PatternLayoutEncoder encoder = (PatternLayoutEncoder) consoleApp
+                            .getEncoder();
+                    app.setEncoderPattern(encoder.getPattern());
+                    app.setName(consoleApp.getName());
+                    app.setThresholdFilter(context.getLogger(
+                            Logger.ROOT_LOGGER_NAME).getEffectiveLevel().levelStr);
+                    this.consoleDTOs.put(consoleApp.getName(), app);
+                }
+            }
+        }
+    }
+
+    private Map<String, LoggerTO> prepareLoggersDTOs(
+            LoggerContext context) {
+        Map<String, LoggerTO> DTOs = new HashMap<>();
+        List<String> appenders = new ArrayList<>();
+        List<org.slf4j.Logger> loggersToBeAdd = removeUnusableLoggers(
+                context.getLoggerList(),
+                context.getLogger(Logger.ROOT_LOGGER_NAME));
+        for (org.slf4j.Logger log : loggersToBeAdd) {
+            LoggerTO logger = new LoggerTO();
+            if (((Logger) log).getLevel() != null)
+                logger.setLevel(((Logger) log).getLevel().levelStr);
+            else
+                logger.setLevel(((Logger) log).getEffectiveLevel().levelStr);
+            logger.setLoggerName(log.getName());
+            Iterator<Appender<ILoggingEvent>> iter = ((Logger) log)
+                    .iteratorForAppenders();
+            while (iter.hasNext()) {
+                Appender<ILoggingEvent> element = iter.next();
+                appenders.add(element.getName());
+            }
+            logger.setAppenders(appenders);
+            DTOs.put(log.getName(), logger);
+            appenders = new ArrayList<>();
+
+        }
+        return DTOs;
+    }
+
+    private List<org.slf4j.Logger> removeUnusableLoggers(
+            List<Logger> loggerList, Logger rootLogger) {
+        Collections.sort(loggerList, new LoggerComparator());
+        Map<String, org.slf4j.Logger> loggersToReturn = new HashMap<>();
+
+        for (org.slf4j.Logger log : loggerList) {
+            boolean shouldAdd = true;
+            for (Entry<String, org.slf4j.Logger> entry : loggersToReturn
+                    .entrySet()) {
+                if (StringUtils.contains(log.getName(), entry.getKey())) {
+                    if (((Logger) log).getLevel() != null
+                            && ((Logger) log).getLevel().equals(
+                                    ((Logger) entry.getValue()).getLevel())
+                            && !((Logger) log).iteratorForAppenders().hasNext()) {
+                        shouldAdd = false;
+                        break;
+                    }
+                    if (((Logger) log).getLevel() == null
+                            && ((Logger) log).getEffectiveLevel().equals(
+                                    ((Logger) entry.getValue())
+                                            .getEffectiveLevel())
+                            && !((Logger) log).iteratorForAppenders().hasNext()) {
+                        shouldAdd = false;
+                        break;
+                    }
+                }
+                if (((Logger) log).getLevel() != null
+                        && ((Logger) log).getLevel().equals(
+                                rootLogger.getLevel())
+                        && !((Logger) log).iteratorForAppenders().hasNext()) {
+                    shouldAdd = false;
+                    break;
+                }
+                if (((Logger) log).getLevel() == null
+                        && ((Logger) log).getEffectiveLevel().equals(
+                                rootLogger.getEffectiveLevel())
+                        && !((Logger) log).iteratorForAppenders().hasNext()) {
+                    shouldAdd = false;
+                    break;
+                }
+            }
+            if (shouldAdd) {
+                loggersToReturn.put(log.getName(), log);
+            }
+        }
+        return Lists.newArrayList(loggersToReturn.values());
+    }
+
+}
diff --git a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackStatusListener.java b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackStatusListener.java
new file mode 100644 (file)
index 0000000..dc26779
--- /dev/null
@@ -0,0 +1,121 @@
+/**
+ * Generated file
+
+ * Generated from: yang module name: config-test  yang module local name: testing
+ * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ * Generated at: Fri Sep 27 14:06:33 CEST 2013
+ *
+ * Do not modify this file unless it is present under src/main directory
+ */
+package org.opendaylight.controller.config.yang.logback.config;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import ch.qos.logback.core.status.Status;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.core.status.StatusBase;
+import ch.qos.logback.core.status.StatusListener;
+import ch.qos.logback.core.status.StatusManager;
+
+public class LogbackStatusListener implements StatusListener,
+        LogbackRuntimeMXBean, Closeable {
+
+    private final List<StatusTO> receivedStatuses;
+    private final LogbackRuntimeRegistrator rootRuntimeBeanRegistratorWrapper;
+    private LogbackRuntimeRegistration reg;
+
+    public LogbackStatusListener(
+            LogbackRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) {
+        receivedStatuses = new ArrayList<>();
+        this.rootRuntimeBeanRegistratorWrapper = rootRuntimeBeanRegistratorWrapper;
+    }
+
+    @Override
+    public synchronized List<StatusTO> getStatusTO() {
+        return Collections.unmodifiableList(receivedStatuses);
+    }
+
+    @Override
+    public synchronized void reset() {
+        receivedStatuses.clear();
+    }
+
+    public LogbackRuntimeRegistration register() {
+        reg = registerToJMX(rootRuntimeBeanRegistratorWrapper);
+        registerToLogback();
+        return reg;
+    }
+
+    private LogbackRuntimeRegistration registerToJMX(
+            LogbackRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) {
+        return rootRuntimeBeanRegistratorWrapper.register(this);
+    }
+
+    private synchronized void registerToLogback() {
+        LoggerContext context = (LoggerContext) LoggerFactory
+                .getILoggerFactory();
+        final StatusManager statusManager = context.getStatusManager();
+
+        statusManager.remove(this);
+        reset();
+
+        statusManager.add(this);
+        addInitialStatuses(statusManager);
+    }
+
+    private void addInitialStatuses(StatusManager statusManager) {
+        for (ch.qos.logback.core.status.Status status : statusManager
+                .getCopyOfStatusList()) {
+            addStatusEvent(status);
+        }
+    }
+
+    @Override
+    public synchronized void addStatusEvent(
+            ch.qos.logback.core.status.Status status) {
+        receivedStatuses.add(transformStatus(status));
+    }
+
+    private StatusTO transformStatus(ch.qos.logback.core.status.Status status) {
+        StatusTO transformed = new StatusTO();
+
+        transformed.setDate(status.getDate());
+        transformed.setLevel(transformStatusLevel(status.getLevel()));
+        transformed.setMessage(status.getMessage());
+
+        return transformed;
+    }
+
+    private String transformStatusLevel(int status) {
+        switch (status) {
+        case StatusBase.INFO:
+            return "INFO";
+        case StatusBase.WARN:
+            return "WARN";
+        case StatusBase.ERROR:
+            return "ERROR";
+        default:
+            throw new IllegalStateException("Unknown status level " + status);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (reg != null)
+            reg.close();
+        unregisterFromLogback();
+    }
+
+    private void unregisterFromLogback() {
+        LoggerContext context = (LoggerContext) LoggerFactory
+                .getILoggerFactory();
+        final StatusManager statusManager = context.getStatusManager();
+        statusManager.remove(this);
+    }
+}
diff --git a/opendaylight/config/logback-config/src/main/yang/config-logging.yang b/opendaylight/config/logback-config/src/main/yang/config-logging.yang
new file mode 100644 (file)
index 0000000..d0307f6
--- /dev/null
@@ -0,0 +1,152 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module config-logging {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:logback:config";
+    prefix "logging";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+
+    organization "Cisco Systems, Inc.";
+
+    description
+        "This module contains the base YANG definitions for NS-OS
+         logging module.";
+
+    revision "2013-07-16" {
+        description
+            "Initial revision.";
+    }
+
+    identity logback {
+        description
+            "Actual state of logback configuration.";
+        base config:module-type;
+        config:java-name-prefix Logback;
+    }
+
+    identity logback-rpc;
+
+    augment "/config:modules/config:module/config:configuration" {
+        case logback {
+            when "/config:modules/config:module/config:type = 'logback'";
+
+            list rolling-appenders {
+                leaf append {
+                    type boolean;
+                    mandatory false;
+                }
+
+                leaf file-name {
+                    type string;
+                    mandatory true;
+                }
+
+                leaf encoder-pattern {
+                    type string;
+                    mandatory true;
+                }
+
+                leaf min-index {
+                    type int32;
+                    mandatory true;
+                }
+
+                leaf max-index {
+                    type int32;
+                    mandatory true;
+                }
+
+                leaf max-file-size {
+                    type string;
+                    mandatory true;
+                }
+
+                leaf name {
+                    type string;
+                    mandatory true;
+                }
+
+                leaf file-name-pattern {
+                    type string;
+                    mandatory true;
+                }
+
+                config:java-name-prefix RollingFileAppenderTO;
+            }
+
+            list console-appenders {
+
+                leaf encoder-pattern {
+                    type string;
+                    mandatory true;
+                }
+
+                leaf threshold-filter {
+                    type string;
+                    default 'ALL';
+                }
+
+                leaf name {
+                    type string;
+                    mandatory true;
+                }
+                config:java-name-prefix ConsoleAppenderTO;
+            }
+
+            list loggers {
+                leaf logger-name {
+                    type string;
+                    mandatory true;
+                }
+
+                leaf level {
+                    type string;
+                    mandatory true;
+                }
+
+                leaf-list appenders {
+                    type string;
+                }
+                config:java-name-prefix LoggerTO;
+            }
+        }
+    }
+
+
+    augment "/config:modules/config:module/config:state" {
+        case logback {
+            when "/config:modules/config:module/config:type = 'logback'";
+
+            rpcx:rpc-context-instance "logback-rpc";
+
+            list status {
+                config:java-name-prefix StatusTO;
+
+                leaf level {
+                    type string;
+                }
+
+                leaf message {
+                    type string;
+                }
+
+                leaf date {
+                    type uint32;
+                }
+            }
+        }
+    }
+
+    rpc reset {
+        input {
+            uses rpcx:rpc-context-ref {
+                refine context-instance {
+                    rpcx:rpc-context-instance logback-rpc;
+                }
+            }
+        }
+    }
+
+}
+
diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImplTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImplTest.java
new file mode 100644 (file)
index 0000000..7ba7a24
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.logback.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+
+public class ContextSetterImplTest {
+
+    @Mock
+    private LogbackRuntimeRegistrator runtimeRegistratorMock;
+    @Mock
+    private DependencyResolver dependencyResolverMock;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        LogbackRuntimeRegistration reg = mock(LogbackRuntimeRegistration.class);
+        doReturn(reg).when(runtimeRegistratorMock).register(
+                any(LogbackRuntimeMXBean.class));
+    }
+
+    @Test
+    public void testUpdate() throws Exception {
+        Multimap<String, String> loggersToAppenders = HashMultimap.create();
+        loggersToAppenders.put("l1", "a1");
+        loggersToAppenders.put("l1", "a2");
+        createContextSetter(loggersToAppenders);
+
+        assertLoggerWithAppenders("l1", "a1", "a2");
+    }
+
+    @Test
+    public void testUpdateTwice() throws Exception {
+        Multimap<String, String> loggersToAppenders = HashMultimap.create();
+        loggersToAppenders.put("l1", "a1");
+        loggersToAppenders.put("l1", "a2");
+        createContextSetter(loggersToAppenders);
+
+        loggersToAppenders.clear();
+        loggersToAppenders.put("l1", "a3");
+        loggersToAppenders.put("l1", "a2");
+        loggersToAppenders.put("l1", "a4");
+        createContextSetter(loggersToAppenders);
+
+        assertLoggerWithAppenders("l1", "a2", "a3", "a4");
+    }
+
+    @Test
+    public void testKeepOtherLoggers() throws Exception {
+        Multimap<String, String> loggersToAppenders = HashMultimap.create();
+        loggersToAppenders.put("l1", "a1");
+        loggersToAppenders.put("l1", "a2");
+        loggersToAppenders.put("l2", "a22");
+        createContextSetter(loggersToAppenders);
+
+        loggersToAppenders.clear();
+        loggersToAppenders.put("l1", "a3");
+        createContextSetter(loggersToAppenders);
+
+        assertLoggerWithAppenders("l1", "a3");
+        assertLoggerWithAppenders("l2", "a22");
+    }
+
+    private void createContextSetter(Multimap<String, String> loggersToAppenders) {
+        ContextSetterImpl setter = new ContextSetterImpl(runtimeRegistratorMock);
+
+        List<LoggerTO> logger = Lists.newArrayList();
+        List<ConsoleAppenderTO> consoleAppenders = Lists.newArrayList();
+
+        for (String loggerName : loggersToAppenders.keySet()) {
+            LoggerTO l1 = createLogger(loggerName,
+                    loggersToAppenders.get(loggerName));
+            logger.add(l1);
+            for (String appenderName : loggersToAppenders.get(loggerName)) {
+                consoleAppenders.add(createConsoleAppender(appenderName));
+            }
+
+        }
+
+        LogbackModule logbackModule = createLogbackModule(logger,
+                consoleAppenders);
+        setter.updateContext(logbackModule);
+    }
+
+    private void assertLoggerWithAppenders(String name, String... appenders) {
+        LoggerContext context = (LoggerContext) LoggerFactory
+                .getILoggerFactory();
+        ch.qos.logback.classic.Logger logger = context.getLogger(name);
+        Iterator<Appender<ILoggingEvent>> it = logger.iteratorForAppenders();
+
+        Multimap<String, Appender<?>> foundAppenders = HashMultimap.create();
+        while (it.hasNext()) {
+            final Appender<ILoggingEvent> app = it.next();
+            foundAppenders.put(app.getName(), app);
+        }
+
+        if (appenders.length == 0) {
+            assertEquals(0, foundAppenders.values().size());
+        }
+
+        for (String appender : appenders) {
+            boolean isPresent = foundAppenders.get(appender).isEmpty();
+            assertFalse(
+                    "Appender " + appender + " for logger " + name
+                            + " was not present, present appenders: "
+                            + foundAppenders.keys(), isPresent);
+        }
+
+    }
+
+    private LogbackModule createLogbackModule(List<LoggerTO> logger,
+            List<ConsoleAppenderTO> consoleAppenders) {
+        LogbackModule logbackModule = new LogbackModule(new ModuleIdentifier(
+                "fact", "first"), dependencyResolverMock);
+        logbackModule.setLoggerTO(logger);
+        logbackModule.setConsoleAppenderTO(consoleAppenders);
+        logbackModule.setRollingFileAppenderTO(Lists
+                .<RollingFileAppenderTO> newArrayList());
+        return logbackModule;
+    }
+
+    private LoggerTO createLogger(String name, Collection<String> appenders) {
+        LoggerTO l1 = new LoggerTO();
+        l1.setAppenders(Lists.newArrayList(appenders));
+        l1.setLoggerName(name);
+        l1.setLevel("INFO");
+        return l1;
+    }
+
+    private ConsoleAppenderTO createConsoleAppender(String name) {
+        ConsoleAppenderTO a = new ConsoleAppenderTO();
+        a.setName(name);
+        a.setEncoderPattern("%-4relative [%thread] %-5level %logger{35} - %msg%n");
+        return a;
+    }
+}
diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java
new file mode 100644 (file)
index 0000000..1e2327e
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.logback.config;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.jmx.CommitStatus;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+
+public class LogbackModuleTest extends AbstractConfigTest {
+
+    private static final String INSTANCE_NAME = "singleton";
+
+    private LogbackModuleFactory factory;
+
+    @Before
+    public void setUp() throws IOException, ClassNotFoundException,
+            InterruptedException {
+
+        factory = new LogbackModuleFactory();
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(
+                factory));
+    }
+
+    @Test
+    public void testCreateBean() throws InstanceAlreadyExistsException {
+
+        CommitStatus status = createBeans(
+        true, "target/rollingApp",
+                "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB",
+                1, 5, "target/%i.log", "rolling", "consoleName", "ALL",
+                "logger1", "DEBUG").commit();
+
+        assertBeanCount(1, factory.getImplementationName());
+        assertStatus(status, 1, 0, 0);
+    }
+
+    @Test
+    public void testReusingInstance() throws InstanceAlreadyExistsException {
+        createBeans(
+        true, "target/rollingApp",
+                "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB",
+                1, 5, "target/%i.log", "rolling", "consoleName", "ALL",
+                "logger1", "DEBUG").commit();
+
+        assertBeanCount(1, factory.getImplementationName());
+
+        ConfigTransactionJMXClient transaction = configRegistryClient
+                .createTransaction();
+        CommitStatus status = transaction.commit();
+
+        assertBeanCount(1, factory.getImplementationName());
+        assertStatus(status, 0, 0, 1);
+    }
+
+    @Test
+    public void testRecreateInstance() throws InstanceAlreadyExistsException,
+            ValidationException, ConflictingVersionException,
+            InstanceNotFoundException {
+        createBeans(
+        true, "target/rollingApp",
+                "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB",
+                1, 5, "target/%i.log", "rolling", "consoleName", "ALL",
+                "logger1", "DEBUG").commit();
+
+        assertBeanCount(1, LogbackModuleFactory.NAME);
+        ConfigTransactionJMXClient transaction = configRegistryClient
+                .createTransaction();
+
+        ObjectName logback = transaction.lookupConfigBean(
+                LogbackModuleFactory.NAME, "singleton");
+        LogbackModuleMXBean nwBean = transaction.newMXBeanProxy(logback,
+                LogbackModuleMXBean.class);
+        CommitStatus status = transaction.commit();
+        assertBeanCount(1, LogbackModuleFactory.NAME);
+
+        assertStatus(status, 0, 0, 1);
+    }
+
+    @Test
+    public void testDestroyInstance() throws InstanceNotFoundException,
+            InstanceAlreadyExistsException {
+        createBeans(
+        true, "target/rollingApp",
+                "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB",
+                1, 5, "target/%i.log", "rolling", "consoleName", "ALL",
+                "logger1", "DEBUG").commit();
+        assertBeanCount(1, factory.getImplementationName());
+
+        ConfigTransactionJMXClient transaction = configRegistryClient
+                .createTransaction();
+        transaction.destroyConfigBean(factory.getImplementationName(),
+                INSTANCE_NAME);
+        CommitStatus status = transaction.commit();
+
+        assertBeanCount(0, factory.getImplementationName());
+        assertStatus(status, 0, 0, 0);
+    }
+
+    @Ignore
+    @Test
+    public void testValidation1() throws InstanceAlreadyExistsException {
+        try {
+            createBeans(
+            true, "target/rollingApp",
+                    "%-4relative [%thread] %-5level %logger{35} - %msg%n",
+                    "30MB", 1, 5, "target/%i.log", "rolling", "consoleName",
+                    "ALL", "logger1", "DEBUG").commit();
+            fail();
+        } catch (ValidationException e) {
+            assertThat(e.getFailedValidations().toString(),
+                    containsString("FileName is null"));
+        }
+    }
+
+    @Test
+    public void testValidation2() throws InstanceAlreadyExistsException {
+        try {
+            createBeans(
+            true, "target/rollingApp", null, "30MB", 1, 5, "target/%i.log",
+                    "rolling", "consoleName", "ALL", "logger1", "DEBUG")
+                    .commit();
+            fail();
+        } catch (ValidationException e) {
+            assertThat(e.getFailedValidations().toString(),
+                    containsString("EncoderPattern is null"));
+        }
+    }
+
+    @Test
+    public void testValidation4() throws InstanceAlreadyExistsException {
+        try {
+            createBeans(
+            true, "target/rollingApp",
+                    "%-4relative [%thread] %-5level %logger{35} - %msg%n",
+                    null, 1, 5, "target/%i.log", "rolling", "consoleName",
+                    "ALL", "logger1", "DEBUG").commit();
+            fail();
+        } catch (ValidationException e) {
+            assertThat(e.getFailedValidations().toString(),
+                    containsString("MaxFileSize is null"));
+        }
+    }
+
+    @Test
+    public void testValidation6() throws InstanceAlreadyExistsException {
+        try {
+            createBeans(
+            true, "", "%-4relative [%thread] %-5level %logger{35} - %msg%n",
+                    "30MB", 1, 5, "target/%i.log", "rolling", "consoleName",
+                    "ALL", "logger1", "DEBUG").commit();
+            fail();
+        } catch (ValidationException e) {
+            assertThat(e.getFailedValidations().toString(),
+                    containsString("FileName needs to be set"));
+        }
+    }
+
+    @Test
+    public void testValidation7() throws InstanceAlreadyExistsException {
+        try {
+            createBeans(
+
+            true, "target/rollingApp", "", "30MB", 1, 5, "target/%i.log",
+                    "rolling", "consoleName", "ALL", "logger1", "DEBUG")
+                    .commit();
+            fail();
+        } catch (ValidationException e) {
+            assertThat(e.getFailedValidations().toString(),
+                    containsString("EncoderPattern needs to be set"));
+        }
+    }
+
+    @Test
+    public void testValidation8() throws InstanceAlreadyExistsException {
+        try {
+            createBeans(
+            true, "target/rollingApp",
+                    "%-4relative [%thread] %-5level %logger{35} - %msg%n",
+                    "30MB", 1, 5, "target/%i.log", "rolling", "consoleName",
+                    "ALL", null, "DEBUG").commit();
+            fail();
+        } catch (ValidationException e) {
+            assertThat(e.getFailedValidations().toString(),
+                    containsString("LoggerName is null"));
+        }
+    }
+
+    @Test
+    public void testValidation9() throws InstanceAlreadyExistsException {
+        try {
+            createBeans(
+            true, "target/rollingApp",
+                    "%-4relative [%thread] %-5level %logger{35} - %msg%n",
+                    "30MB", 1, 5, "target/%i.log", "rolling", "consoleName",
+                    "ALL", "", "DEBUG").commit();
+            fail();
+        } catch (ValidationException e) {
+            assertThat(e.getFailedValidations().toString(),
+                    containsString("LoggerName needs to be set"));
+        }
+    }
+
+    @Test
+    public void testValidation10() throws InstanceAlreadyExistsException {
+        try {
+            createBeans(
+            true, "target/rollingApp",
+                    "%-4relative [%thread] %-5level %logger{35} - %msg%n",
+                    "30MB", null, 5, "target/%i.log", "rolling", "consoleName",
+                    "ALL", "logger1", "DEBUG").commit();
+            fail();
+        } catch (ValidationException e) {
+            assertThat(e.getFailedValidations().toString(),
+                    containsString("MinIndex is null"));
+        }
+    }
+
+    @Test
+    public void testValidation11() throws InstanceAlreadyExistsException {
+        try {
+            createBeans(
+            true, "target/rollingApp",
+                    "%-4relative [%thread] %-5level %logger{35} - %msg%n",
+                    "30MB", 1, null, "target/%i.log", "rolling", "consoleName",
+                    "ALL", "logger1", "DEBUG").commit();
+            fail();
+        } catch (ValidationException e) {
+            assertThat(e.getFailedValidations().toString(),
+                    containsString("MaxIndex is null"));
+        }
+    }
+
+    private ConfigTransactionJMXClient createBeans(
+    Boolean isAppend, String rollingFileName, String encoderPattern,
+            String maxFileSize, Integer minIndex, Integer maxIndex,
+            String fileNamePattern, String rollingName, String consoleName,
+            String thresholdFilter, String loggerName, String level )
+            throws InstanceAlreadyExistsException {
+        ConfigTransactionJMXClient transaction = configRegistryClient
+                .createTransaction();
+        ObjectName nameCreated = transaction.createModule(
+                factory.getImplementationName(), INSTANCE_NAME);
+        LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated,
+                LogbackModuleMXBean.class);
+
+        List<RollingFileAppenderTO> rollingAppenders = new ArrayList<>();
+        RollingFileAppenderTO rollingAppender = new RollingFileAppenderTO();
+        rollingAppender.setAppend(isAppend);
+        rollingAppender.setEncoderPattern(encoderPattern);
+        rollingAppender.setFileName(rollingFileName);
+        rollingAppender.setMaxFileSize(maxFileSize);
+        rollingAppender.setMaxIndex(maxIndex);
+        rollingAppender.setMinIndex(minIndex);
+        rollingAppender.setFileNamePattern(fileNamePattern);
+        rollingAppender.setName(rollingName);
+        rollingAppenders.add(rollingAppender);
+
+        List<ConsoleAppenderTO> consoleAppenders = new ArrayList<>();
+        ConsoleAppenderTO consoleAppender = new ConsoleAppenderTO();
+        consoleAppender.setEncoderPattern(encoderPattern);
+        consoleAppender.setName(consoleName);
+        consoleAppender.setThresholdFilter(thresholdFilter);
+        consoleAppenders.add(consoleAppender);
+
+        List<LoggerTO> loggers = new ArrayList<>();
+
+        LoggerTO logger = new LoggerTO();
+
+        logger.setAppenders(Arrays.<String> asList());
+
+        logger.setLevel(level);
+        logger.setLoggerName(loggerName);
+        loggers.add(logger);
+        bean.setLoggerTO(loggers);
+        bean.setRollingFileAppenderTO(rollingAppenders);
+        bean.setConsoleAppenderTO(consoleAppenders);
+
+        transaction.validateConfig();
+
+        return transaction;
+    }
+
+}
diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java
new file mode 100644 (file)
index 0000000..2bdfa47
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.logback.config;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.JMX;
+import javax.management.ObjectName;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
+import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
+
+import com.google.common.collect.Lists;
+
+public class LogbackModuleWithInitialConfigurationTest extends
+        AbstractConfigTest {
+
+    private LogbackModuleFactory factory;
+
+    @Before
+    public void setUp() throws IOException, ClassNotFoundException {
+
+        factory = new LogbackModuleFactory();
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(
+                factory));
+    }
+
+    /**
+     * Tests that initial configuration was changed. Changed attributes:
+     * location, fileName, duplicateInsertTries
+     *
+     */
+    @Test
+    public void test() throws Exception {
+
+        createBeans();
+
+        ConfigTransactionClient transaction = configRegistryClient
+                .createTransaction();
+
+        LogbackModuleMXBean bean = JMX.newMXBeanProxy(
+                ManagementFactory.getPlatformMBeanServer(),
+                transaction.lookupConfigBean("logback", "singleton"),
+                LogbackModuleMXBean.class);
+        assertEquals(1, bean.getConsoleAppenderTO().size());
+        assertEquals(1, bean.getRollingFileAppenderTO().size());
+        assertEquals(1, bean.getLoggerTO().size());
+
+        RollingFileAppenderTO rolling = new RollingFileAppenderTO();
+        RollingFileAppenderTO old = bean
+                .getRollingFileAppenderTO().get(0);
+        rolling.setAppend(old.getAppend());
+        rolling.setEncoderPattern(old.getEncoderPattern());
+        rolling.setFileName("target/logFile1.log");
+        rolling.setFileNamePattern("target/%i.log");
+        rolling.setMaxFileSize(old.getMaxFileSize());
+        rolling.setMinIndex(old.getMinIndex());
+        rolling.setMaxIndex(old.getMaxIndex());
+        rolling.setName("FILE");
+
+        ConsoleAppenderTO console = new ConsoleAppenderTO();
+        console.setEncoderPattern("%date %level [%thread] %logger{10} %msg%n");
+        console.setName("SYSTEM");
+        console.setThresholdFilter("DEBUG");
+
+        bean.setConsoleAppenderTO(Lists.newArrayList(console));
+        bean.setRollingFileAppenderTO(Lists.newArrayList(rolling));
+
+        LoggerTO logger = new LoggerTO();
+        logger.setLevel("INFO");
+        logger.setLoggerName("logger");
+        logger.setAppenders(Lists.newArrayList("SYSTEM"));
+        List<LoggerTO> loggers = Lists
+                .newArrayList(logger);
+        bean.setLoggerTO(loggers);
+
+        transaction.commit();
+
+        LogbackModuleMXBean logback = configRegistryClient.newMXBeanProxy(
+                ObjectNameUtil.createReadOnlyModuleON("logback", "singleton"),
+                LogbackModuleMXBean.class);
+
+
+        List<RollingFileAppenderTO> rollingList = logback
+                .getRollingFileAppenderTO();
+        assertEquals(1, rollingList.size());
+
+        RollingFileAppenderTO rollingApp = rollingList
+                .get(0);
+        assertEquals(rollingApp.getFileName(), "target/logFile1.log");
+        assertEquals(rollingApp.getName(), "FILE");
+
+        List<ConsoleAppenderTO> consoleList = logback
+                .getConsoleAppenderTO();
+        assertEquals(1, consoleList.size());
+
+        ConsoleAppenderTO consoleApp = consoleList
+                .get(0);
+        assertEquals(consoleApp.getThresholdFilter(), "DEBUG");
+        assertEquals(consoleApp.getName(), "SYSTEM");
+
+        loggers = logback.getLoggerTO();
+        assertEquals(1, loggers.size());
+
+    }
+
+    public ObjectName createBeans() throws JoranException,
+            InstanceAlreadyExistsException, IOException {
+
+        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+
+        JoranConfigurator configurator = new JoranConfigurator();
+        configurator.setContext(lc);
+        configurator
+                .doConfigure("src/test/resources/simple_config_logback.xml");
+        File f = new File("target/it");
+        if (f.exists())
+            FileUtils.cleanDirectory(f);
+        ch.qos.logback.classic.Logger logger = lc.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
+        ch.qos.logback.core.rolling.RollingFileAppender<ILoggingEvent> fileAppender = (ch.qos.logback.core.rolling.RollingFileAppender<ILoggingEvent>) logger
+                .getAppender("VARLOGFILE");
+        fileAppender.start();
+
+        ch.qos.logback.core.ConsoleAppender<ILoggingEvent> consoleAppender = (ch.qos.logback.core.ConsoleAppender<ILoggingEvent>) logger
+                .getAppender("STDOUT");
+        consoleAppender.start();
+        List<RollingFileAppenderTO> rollingAppenders = new ArrayList<>();
+        RollingFileAppenderTO rollingApp = new RollingFileAppenderTO();
+        rollingApp.setAppend(fileAppender.isAppend());
+        PatternLayoutEncoder enc = (PatternLayoutEncoder) fileAppender
+                .getEncoder();
+        rollingApp.setEncoderPattern(enc.getPattern());
+        rollingApp.setFileName(fileAppender.getFile());
+        FixedWindowRollingPolicy rollingPolicy = (FixedWindowRollingPolicy) fileAppender
+                .getRollingPolicy();
+        rollingApp.setMaxIndex(rollingPolicy.getMaxIndex());
+        rollingApp.setMinIndex(rollingPolicy.getMinIndex());
+        SizeBasedTriggeringPolicy<ILoggingEvent> triggeringPolicy = (SizeBasedTriggeringPolicy<ILoggingEvent>) fileAppender
+                .getTriggeringPolicy();
+        rollingApp.setMaxFileSize(triggeringPolicy.getMaxFileSize());
+        rollingApp.setName(fileAppender.getName());
+        rollingApp.setFileNamePattern(rollingPolicy.getFileNamePattern());
+        rollingAppenders.add(rollingApp);
+
+        assertEquals(rollingApp.getFileName(), "target/osgi.log");
+        assertEquals(rollingApp.getMaxFileSize(), "50MB");
+        assertEquals(rollingApp.getName(), "VARLOGFILE");
+
+        List<ConsoleAppenderTO> consoleAppenders = new ArrayList<>();
+        ConsoleAppenderTO consoleApp = new ConsoleAppenderTO();
+        enc = (PatternLayoutEncoder) consoleAppender.getEncoder();
+        consoleApp.setEncoderPattern(enc.getPattern());
+        consoleApp.setName(consoleAppender.getName());
+        consoleApp.setThresholdFilter("ALL");
+        consoleAppenders.add(consoleApp);
+
+        List<LoggerTO> loggersDTOs = new ArrayList<>();
+        LoggerTO log = new LoggerTO();
+        log.setAppenders(Arrays.asList(fileAppender.getName(),
+                consoleApp.getName()));
+
+        log.setLevel(logger.getLevel().toString());
+        log.setLoggerName(logger.getName());
+        loggersDTOs.add(log);
+
+        ConfigTransactionJMXClient transaction = configRegistryClient
+                .createTransaction();
+        ObjectName nameCreated = transaction.createModule(
+                factory.getImplementationName(), "singleton");
+        LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated,
+                LogbackModuleMXBean.class);
+
+        bean.setLoggerTO(loggersDTOs);
+        bean.setRollingFileAppenderTO(rollingAppenders);
+        bean.setConsoleAppenderTO(consoleAppenders);
+
+        transaction.commit();
+
+        return nameCreated;
+    }
+}
diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java
new file mode 100644 (file)
index 0000000..ce3a019
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.logback.config;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMX;
+import javax.management.ObjectName;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+
+public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest {
+
+    private LogbackModuleFactory factory;
+    private LoggerContext lc;
+
+    @Before
+    public void setUp() throws JoranException, IOException {
+
+        factory = new LogbackModuleFactory();
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(
+                factory));
+
+        lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+        JoranConfigurator configurator = new JoranConfigurator();
+        lc.reset();
+        configurator.setContext(lc);
+        configurator
+                .doConfigure("src/test/resources/simple_config_logback.xml");
+        File f = new File("target/it");
+        if (f.exists())
+            FileUtils.cleanDirectory(f);
+    }
+
+    /**
+     * Tests configuration of Logger factory.
+     */
+    @Test
+    public void test() throws InstanceAlreadyExistsException,
+            InstanceNotFoundException {
+
+        ConfigTransactionJMXClient transaction = configRegistryClient
+                .createTransaction();
+        ObjectName nameCreated = transaction.createModule(
+                factory.getImplementationName(), "singleton");
+
+        LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated,
+                LogbackModuleMXBean.class);
+
+        assertEquals(1, bean.getConsoleAppenderTO().size());
+
+        assertEquals(1, bean.getRollingFileAppenderTO().size());
+
+        transaction.commit();
+
+        transaction = configRegistryClient.createTransaction();
+
+        nameCreated = transaction.lookupConfigBean(
+                factory.getImplementationName(), "singleton");
+
+        bean = JMX.newMXBeanProxy(platformMBeanServer, nameCreated,
+                LogbackModuleMXBean.class);
+
+        assertEquals(1, bean.getConsoleAppenderTO().size());
+        assertEquals(1, bean.getRollingFileAppenderTO().size());
+
+    }
+
+    /**
+     * Tests filtering loggers. Loggers inherited from ROOT logger and duplicate
+     * loggers should be removed.
+     */
+    @Test
+    public void testAllLoggers() throws InstanceAlreadyExistsException,
+            InstanceNotFoundException {
+        ConfigTransactionJMXClient transaction = configRegistryClient
+                .createTransaction();
+        transaction.createModule(factory.getImplementationName(), "singleton");
+
+        transaction.commit();
+
+        transaction = configRegistryClient.createTransaction();
+
+        LogbackModuleMXBean bean = JMX.newMXBeanProxy(
+                ManagementFactory.getPlatformMBeanServer(),
+                transaction.lookupConfigBean("logback", "singleton"),
+                LogbackModuleMXBean.class);
+
+        assertEquals(5, bean.getLoggerTO().size());
+    }
+
+}
diff --git a/opendaylight/config/logback-config/src/test/resources/simple_config_logback.xml b/opendaylight/config/logback-config/src/test/resources/simple_config_logback.xml
new file mode 100644 (file)
index 0000000..f4535de
--- /dev/null
@@ -0,0 +1,76 @@
+<configuration>
+
+    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+        <resetJUL>true</resetJUL>
+    </contextListener>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+        <encoder>
+            <pattern>[%d{HH:mm:ss.SSS}] [%thread] %-5level %logger - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <!-- rolling file /var/log/osgi/osgi.log that keeps last 3 backups of 5MB -->
+    <appender name="VARLOGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>target/osgi.log</file>
+        <append>true</append>
+        <encoder>
+            <pattern>[%d{HH:mm:ss.SSS}] [%thread] %-5level %logger - %msg%n</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+            <fileNamePattern>/opt/Demo1/logs/osgi.log.%i.gz</fileNamePattern>
+            <minIndex>1</minIndex>
+            <maxIndex>5</maxIndex>
+        </rollingPolicy>
+
+        <triggeringPolicy
+                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <maxFileSize>50MB</maxFileSize>
+        </triggeringPolicy>
+
+    </appender>
+
+    <appender name="BGPDUMPFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>target/bgp.log</file>
+        <append>false</append>
+        <encoder>
+            <pattern>[%d{HH:mm:ss.SSS}] [%thread] %-5level %logger - %msg%n</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+            <fileNamePattern>/opt/Demo1/logs/bgp.log.%i.gz</fileNamePattern>
+            <minIndex>1</minIndex>
+            <maxIndex>5</maxIndex>
+        </rollingPolicy>
+
+        <triggeringPolicy
+                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <maxFileSize>5MB</maxFileSize>
+        </triggeringPolicy>
+
+    </appender>
+
+
+    <!-- Increase to INFO to see content of REST messages -->
+    <logger name="org.apache.cxf.interceptor.LoggingInInterceptor"
+            level="WARN"/>
+    <logger name="org.apache.cxf.interceptor.LoggingOutInterceptor"
+            level="WARN"/>
+    <!-- Increase to INFO to see content of SOAP messages -->
+    <logger name="org.apache.cxf.services"
+            level="WARN"/>
+    <logger name="org.opendaylight"
+            level="DEBUG"/>
+    <logger name="com"
+            level="INFO"/>
+    <root level="INFO">
+        <!--
+        <appender-ref ref="ALL_APPENDER"/>
+        -->
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="VARLOGFILE"/>
+    </root>
+
+</configuration>
index 7607fb77933dd27490537d697aed03209af0d63e..3ebfad3f3062ef6895c00cb1a6b12479f99e2499 100755 (executable)
@@ -28,6 +28,7 @@
         <module>yang-store-api</module>
         <module>yang-store-impl</module>
         <module>yang-test</module>
+        <module>logback-config</module>
     </modules>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>