You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2008/04/16 11:33:15 UTC

svn commit: r648644 - in /incubator/sling/trunk/osgi/log: ./ src/main/java/org/apache/sling/osgi/log/ src/main/java/org/apache/sling/osgi/log/slf4j/ src/main/java/org/slf4j/ src/main/java/org/slf4j/impl/ src/main/resources/ src/main/resources/OSGI-INF/...

Author: fmeschbe
Date: Wed Apr 16 02:33:11 2008
New Revision: 648644

URL: http://svn.apache.org/viewvc?rev=648644&view=rev
Log:
SLING-384 Replace LogBack by our own simple implementation of the SLF4J API

Added:
    incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogManager.java
      - copied, changed from r647691, incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogbackManager.java
    incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/
    incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriter.java
    incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogWriter.java
    incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogger.java
    incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerFactory.java
    incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerLevel.java
    incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/
    incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/
    incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
    incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticMarkerBinder.java
    incubator/sling/trunk/osgi/log/src/test/
    incubator/sling/trunk/osgi/log/src/test/java/
    incubator/sling/trunk/osgi/log/src/test/java/org/
    incubator/sling/trunk/osgi/log/src/test/java/org/apache/
    incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/
    incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/
    incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/
    incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/
    incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriterTest.java
    incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLoggerTest.java
Removed:
    incubator/sling/trunk/osgi/log/LICENSE.logback
    incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogbackManager.java
    incubator/sling/trunk/osgi/log/src/main/resources/log4j.dtd
    incubator/sling/trunk/osgi/log/src/main/resources/log4j.properties
    incubator/sling/trunk/osgi/log/src/main/resources/log4j.xml
Modified:
    incubator/sling/trunk/osgi/log/pom.xml
    incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/Activator.java
    incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.properties
    incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.xml

Modified: incubator/sling/trunk/osgi/log/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/pom.xml?rev=648644&r1=648643&r2=648644&view=diff
==============================================================================
--- incubator/sling/trunk/osgi/log/pom.xml (original)
+++ incubator/sling/trunk/osgi/log/pom.xml Wed Apr 16 02:33:11 2008
@@ -1,21 +1,21 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
 <!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you 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.
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 
@@ -64,34 +64,22 @@
                             org.apache.commons.logging;version=1.0.4,
                             org.apache.log4j;version=1.2.15,
                             org.slf4j;version=1.4.3,
-                            org.osgi.service.cm,
-                            org.osgi.service.log
+                            org.osgi.service.cm, org.osgi.service.log
                         </Export-Package>
                         <Private-Package>
-                            !ch.qos.logback.classic.db,
-                            !ch.qos.logback.core.db,
-                            !ch.qos.logback.classic.selector.servlet,
-                            ch.qos.logback.*,
                             org.apache.commons.logging.impl,
-                            org.apache.sling.osgi.log, org.slf4j.helpers,
-                            org.slf4j.impl, org.slf4j.spi
+                            org.apache.sling.osgi.log.*,
+                            org.slf4j.helpers, org.slf4j.impl,
+                            org.slf4j.spi
                         </Private-Package>
-                        <DynamicImport-Package>
-                            javax.jms, javax.mail, javax.mail.internet,
-                            javax.management, javax.naming,
-                            javax.xml.parsers, org.codehaus.janino,
-                            org.xml.sax, org.xml.sax.helpers
-                        </DynamicImport-Package>
                     </instructions>
                 </configuration>
             </plugin>
         </plugins>
     </build>
 
-    <!--
-        Core Logging by logback and redirection of commons logging and log4j to SLF4J
-    -->
     <dependencies>
+        <!-- Redirection of commons logging and log4j to SLF4J -->
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>jcl104-over-slf4j</artifactId>
@@ -110,20 +98,6 @@
             <scope>compile</scope>
             <optional>true</optional>
         </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-core</artifactId>
-            <version>0.9.8</version>
-            <scope>compile</scope>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-classic</artifactId>
-            <version>0.9.8</version>
-            <scope>compile</scope>
-            <optional>true</optional>
-        </dependency>
 
         <!-- OSGi Libraries not included here -->
         <dependency>
@@ -135,6 +109,12 @@
             <artifactId>org.osgi.compendium</artifactId>
             <scope>compile</scope>
             <optional>true</optional>
+        </dependency>
+        
+        <!-- testing -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
         </dependency>
     </dependencies>
 </project>

Modified: incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/Activator.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/Activator.java?rev=648644&r1=648643&r2=648644&view=diff
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/Activator.java (original)
+++ incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/Activator.java Wed Apr 16 02:33:11 2008
@@ -33,19 +33,19 @@
  */
 public class Activator implements BundleActivator {
 
-    private LogbackManager logbackManager;
+    private LogManager logManager;
 
     private LogSupport logSupport;
 
     public void start(BundleContext context) throws Exception {
-        this.logbackManager = new LogbackManager(context);
+        logManager = new LogManager(context);
 
-        this.logSupport = new LogSupport();
-        context.addBundleListener(this.logSupport);
-        context.addFrameworkListener(this.logSupport);
-        context.addServiceListener(this.logSupport);
+        logSupport = new LogSupport();
+        context.addBundleListener(logSupport);
+        context.addFrameworkListener(logSupport);
+        context.addServiceListener(logSupport);
 
-        LogServiceFactory lsf = new LogServiceFactory(this.logSupport);
+        LogServiceFactory lsf = new LogServiceFactory(logSupport);
         Dictionary<String, String> props = new Hashtable<String, String>();
         props.put(Constants.SERVICE_PID, lsf.getClass().getName());
         props.put(Constants.SERVICE_DESCRIPTION,
@@ -53,7 +53,7 @@
         props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
         context.registerService(LogService.class.getName(), lsf, props);
 
-        LogReaderServiceFactory lrsf = new LogReaderServiceFactory(this.logSupport);
+        LogReaderServiceFactory lrsf = new LogReaderServiceFactory(logSupport);
         props = new Hashtable<String, String>();
         props.put(Constants.SERVICE_PID, lrsf.getClass().getName());
         props.put(Constants.SERVICE_DESCRIPTION,
@@ -63,7 +63,14 @@
     }
 
     public void stop(BundleContext context) throws Exception {
-        this.logSupport.shutdown();
-        this.logbackManager.shutdown();
+        if (logSupport != null) {
+            logSupport.shutdown();
+            logSupport = null;
+        }
+        
+        if (logManager != null) {
+            logManager.shutdown();
+            logManager = null;
+        }
     }
 }

Copied: incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogManager.java (from r647691, incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogbackManager.java)
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogManager.java?p2=incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogManager.java&p1=incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogbackManager.java&r1=647691&r2=648644&rev=648644&view=diff
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogbackManager.java (original)
+++ incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/LogManager.java Wed Apr 16 02:33:11 2008
@@ -17,48 +17,37 @@
 package org.apache.sling.osgi.log;
 
 import java.io.File;
-import java.io.StringReader;
-import java.net.URL;
+import java.io.IOException;
+import java.text.MessageFormat;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
 
+import org.apache.sling.osgi.log.slf4j.SlingLogFileWriter;
+import org.apache.sling.osgi.log.slf4j.SlingLogWriter;
+import org.apache.sling.osgi.log.slf4j.SlingLogger;
+import org.apache.sling.osgi.log.slf4j.SlingLoggerFactory;
+import org.apache.sling.osgi.log.slf4j.SlingLoggerLevel;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ManagedService;
 import org.slf4j.LoggerFactory;
-import org.xml.sax.InputSource;
-
-import ch.qos.logback.classic.Level;
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.PatternLayout;
-import ch.qos.logback.classic.joran.JoranConfigurator;
-import ch.qos.logback.classic.spi.LoggingEvent;
-import ch.qos.logback.core.Appender;
-import ch.qos.logback.core.ConsoleAppender;
-import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
-import ch.qos.logback.core.rolling.RollingFileAppender;
-import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
 
 /**
- * The <code>LogbackManager</code> manages the loggers used by the LogService
+ * The <code>LogManager</code> manages the loggers used by the LogService
  * and the rest of the system.
  */
-public class LogbackManager implements ManagedService {
+public class LogManager implements ManagedService {
 
     /**
-     * Initial configuration property specifying whether Logback should be
+     * Initial configuration property specifying whether logging should be
      * initialized here or not (value is "org.apache.sling.osgi.log.intialize").
      * If this property is missing or set to <code>true</code>, this class
-     * will reset and configure Logback. Otherwise, Logback is neither reset nor
+     * will reset and configure logging. Otherwise, logging is neither reset nor
      * configured by this class.
-     * <p>
-     * This property may be used to prevent resetting Logback which might be
-     * configured by a container and reused by the Framework.
      */
     public static final String LOG_INITIALIZE = "org.apache.sling.osgi.log.intialize";
 
@@ -74,11 +63,11 @@
 
     public static final String LOG_CONFIG_URL = "org.apache.sling.osgi.log.url";
 
-    public static final String LOG_PATTERN_DEFAULT = "%d{dd.MM.yyyy HH:mm:ss} *%-5p* %c{1}: %m%n";
+    public static final String LOG_PATTERN_DEFAULT = "{0,date,dd.MM.yyyy HH:mm:ss.SSS} *{4}* [{2}] {3} {5}";
 
     public static final int LOG_FILE_NUMBER_DEFAULT = 5;
 
-    public static final String LOG_FILE_SIZE_DEFAULT = "10MB";
+    public static final String LOG_FILE_SIZE_DEFAULT = "10M";
 
     /**
      * default log category - set during init()
@@ -87,59 +76,58 @@
 
     private File rootDir;
 
-    private ServiceRegistration logbackConfigurable;
+    private ServiceRegistration loggingConfigurable;
 
-    /* package */LogbackManager(final BundleContext context) {
+    LogManager(final BundleContext context) {
 
         // the base for relative path names
         String root = context.getProperty("sling.home");
-        this.rootDir = new File((root == null) ? "" : root).getAbsoluteFile();
+        rootDir = new File((root == null) ? "" : root).getAbsoluteFile();
 
         // set initial default configuration
-        this.configureLogback(new ConfigProperties() {
+        configureLogging(new ConfigProperties() {
             public String getProperty(String name) {
                 return context.getProperty(name);
             }
         });
 
         // get our own logger
-        this.log = LoggerFactory.getLogger(LogServiceFactory.class);
-
-        this.log.info("LogbackManager: Logging set up from context");
+        log = LoggerFactory.getLogger(LogServiceFactory.class);
+        log.info("LogManager: Logging set up from context");
 
         // register for official configuration now
         Dictionary<String, String> props = new Hashtable<String, String>();
-        props.put(Constants.SERVICE_PID, LogbackManager.class.getName());
+        props.put(Constants.SERVICE_PID, LogManager.class.getName());
         props.put(Constants.SERVICE_DESCRIPTION,
-            "LogbackManager Configuration Admin support");
+            "LogManager Configuration Admin support");
         props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
 
-        this.logbackConfigurable = context.registerService(
+        loggingConfigurable = context.registerService(
             ManagedService.class.getName(), this, props);
     }
 
-    /* package */void shutdown() {
-        if (this.logbackConfigurable != null) {
-            this.logbackConfigurable.unregister();
-            this.logbackConfigurable = null;
+    void shutdown() {
+        if (loggingConfigurable != null) {
+            loggingConfigurable.unregister();
+            loggingConfigurable = null;
         }
 
         // shutdown the log manager
-        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
-        loggerContext.shutdownAndReset();
+        SlingLoggerFactory loggerFactory = SlingLoggerFactory.getInstance();
+        loggerFactory.close();
     }
 
     // ---------- ManagedService interface -------------------------------------
 
     /*
      * (non-Javadoc)
-     *
+     * 
      * @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary)
      */
     @SuppressWarnings("unchecked")
     public void updated(final Dictionary properties) { // unchecked
         if (properties != null) {
-            this.configureLogback(new ConfigProperties() {
+            configureLogging(new ConfigProperties() {
                 public String getProperty(String name) {
                     final Object obj = properties.get(name);
                     return (obj == null) ? null : obj.toString();
@@ -153,52 +141,48 @@
     /**
      * Start this service. Nothing to be done here.
      */
-    public void reconfigure(URL configLocation) throws Exception {
-        // reset logging first
-        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
-        loggerContext.shutdownAndReset();
-
-        // get the configurator
-        JoranConfigurator configuration = new JoranConfigurator();
-        configuration.setContext(loggerContext);
-
-        // check for log configuration URL and try that first
-        try {
-            configuration.doConfigure(configLocation);
-        } catch (Throwable t) {
-            this.log.error("reconfigure: Cannot configure from {}",
-                configLocation);
-            // well then, fall back to simple configuration
-        }
-
-        this.log.info("reconfigure: Logging reconfigured from ", configLocation);
-    }
-
-    void reconfigure(String data) {
-        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
-        loggerContext.shutdownAndReset();
-
-        // get the configurator
-        JoranConfigurator configuration = new JoranConfigurator();
-        configuration.setContext(loggerContext);
-
-        InputSource source = new InputSource();
-        source.setCharacterStream(new StringReader(data));
-    }
-
+    // public void reconfigure(URL configLocation) throws Exception {
+    // // reset logging first
+    // LoggerContext loggerContext = (LoggerContext)
+    // LoggerFactory.getILoggerFactory();
+    // loggerContext.shutdownAndReset();
+    //
+    // // get the configurator
+    // JoranConfigurator configuration = new JoranConfigurator();
+    // configuration.setContext(loggerContext);
+    //
+    // // check for log configuration URL and try that first
+    // try {
+    // configuration.doConfigure(configLocation);
+    // } catch (Throwable t) {
+    // this.log.error("reconfigure: Cannot configure from {}",
+    // configLocation);
+    // // well then, fall back to simple configuration
+    // }
+    //
+    // this.log.info("reconfigure: Logging reconfigured from ", configLocation);
+    // }
+    // void reconfigure(String data) {
+    // LoggerContext loggerContext = (LoggerContext)
+    // LoggerFactory.getILoggerFactory();
+    // loggerContext.shutdownAndReset();
+    //
+    // // get the configurator
+    // JoranConfigurator configuration = new JoranConfigurator();
+    // configuration.setContext(loggerContext);
+    //
+    // InputSource source = new InputSource();
+    // source.setCharacterStream(new StringReader(data));
+    // }
     public String[] getLoggers() {
         Set<String> loggerSet = new TreeSet<String>();
 
-        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
-        List<Logger> loggers = loggerContext.getLoggerList();
-        for (Logger logger : loggers) {
-            loggerSet.add(logger.getName() + ", level=" + logger.getLevel());
+        SlingLoggerFactory loggerFactory = SlingLoggerFactory.getInstance();
+        List<SlingLogger> loggers = loggerFactory.getLoggerList();
+        for (SlingLogger logger : loggers) {
+            loggerSet.add(logger.getName() + ", level=" + logger.getLogLevel());
         }
 
-        // prepend the root logger
-        Logger root = loggerContext.getLogger(LoggerContext.ROOT_NAME);
-        loggerSet.add("__root__, level=" + root.getLevel());
-
         return loggerSet.toArray(new String[loggerSet.size()]);
     }
 
@@ -208,13 +192,12 @@
             return "Logger name required to set logging level";
         }
 
-        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
-        Logger log = loggerContext.getLogger(logger);
+        SlingLoggerFactory loggerFactory = SlingLoggerFactory.getInstance();
+        SlingLogger log = loggerFactory.getSlingLogger(logger);
         if (log != null) {
-            Level level = Level.toLevel(levelName, log.getLevel());
-            log.setLevel(level);
+            log.setLogLevel(levelName);
 
-            return "Set level '" + level + "' on logger '" + log.getName()
+            return "Set level '" + levelName + "' on logger '" + log.getName()
                 + "'";
         }
 
@@ -223,17 +206,17 @@
     }
 
     /**
-     * Configures Logback from the given properties. This is intended as an
-     * initial configuration. <p/> Sets up the initial Logback properties for
+     * Configures logging from the given properties. This is intended as an
+     * initial configuration. <p/> Sets up the initial logging properties for
      * the logging support until the real logging configuration file can be read
      * from the ContentBus.
-     *
+     * 
      * @param properties The <code>Properties</code> containing the initial
      *            configuration.
      * @throws NullPointerException if <code>properties</code> is
      *             <code>null</code>.
      */
-    protected void configureLogback(ConfigProperties context) {
+    protected void configureLogging(ConfigProperties context) {
 
         // check whether we should configure logging at all
         String initialize = context.getProperty(LOG_INITIALIZE);
@@ -242,39 +225,21 @@
             return;
         }
 
-        // reset logging first
-        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
-        loggerContext.shutdownAndReset();
-
-        // get the configurator
-        JoranConfigurator configuration = new JoranConfigurator();
-        configuration.setContext(loggerContext);
-
         // check for log configuration URL and try that first
-        String logConfig = context.getProperty(LOG_CONFIG_URL);
-        if (logConfig != null && logConfig.length() > 0) {
-            try {
-                URL logConfigURL = new URL(logConfig);
-                configuration.doConfigure(logConfigURL);
-                return;
-            } catch (Throwable t) {
-                // well then, fall back to simple configuration
-            }
-        }
-
-        // set the log appender message pattern
-        String pattern = context.getProperty(LOG_PATTERN);
-        if (pattern == null || pattern.length() == 0) {
-            pattern = LOG_PATTERN_DEFAULT;
-        }
-        PatternLayout pl = new PatternLayout();
-        pl.setPattern(pattern);
-        pl.setContext(loggerContext);
-        pl.start();
+        // String logConfig = context.getProperty(LOG_CONFIG_URL);
+        // if (logConfig != null && logConfig.length() > 0) {
+        // try {
+        // URL logConfigURL = new URL(logConfig);
+        // configuration.doConfigure(logConfigURL);
+        // return;
+        // } catch (Throwable t) {
+        // // well then, fall back to simple configuration
+        // }
+        // }
 
         // if a log file is defined, use the file appender
         String logFileName = context.getProperty(LOG_FILE);
-        Appender<LoggingEvent> appender;
+        SlingLogWriter output;
         if (logFileName != null && logFileName.length() > 0) {
 
             // ensure proper separator in the path
@@ -283,7 +248,7 @@
             // ensure absolute path
             File logFile = new File(logFileName);
             if (!logFile.isAbsolute()) {
-                logFile = new File(this.rootDir, logFileName);
+                logFile = new File(rootDir, logFileName);
                 logFileName = logFile.getAbsolutePath();
             }
 
@@ -307,64 +272,51 @@
                 fileNum = LOG_FILE_NUMBER_DEFAULT;
             }
 
-            // keep the number old log files
-            FixedWindowRollingPolicy rolling = new FixedWindowRollingPolicy();
-            rolling.setFileNamePattern(logFileName + ".%i");
-            rolling.setMinIndex(0);
-            rolling.setMaxIndex(fileNum - 1);
-            rolling.setContext(loggerContext);
-
             // get the log file size
             String fileSize = context.getProperty(LOG_FILE_SIZE);
             if (fileSize == null || fileSize.length() == 0) {
                 fileSize = LOG_FILE_SIZE_DEFAULT;
             }
 
-            // switch log file after 1MB
-            SizeBasedTriggeringPolicy trigger = new SizeBasedTriggeringPolicy();
-            trigger.setMaxFileSize(fileSize);
-            trigger.setContext(loggerContext);
-
-            // define the default appender
-            RollingFileAppender<LoggingEvent> fa = new RollingFileAppender<LoggingEvent>();
-            fa.setFile(logFileName);
-            fa.setAppend(true);
-            fa.setRollingPolicy(rolling);
-            fa.setTriggeringPolicy(trigger);
-
-            // link the roller to the file appender
-            rolling.setParent(fa);
-            rolling.start();
-            trigger.start();
-
-            appender = fa;
+            try {
+                output = new SlingLogFileWriter(logFileName, fileNum, fileSize);
+            } catch (IOException ioe) {
+                SlingLoggerFactory.internalFailure("Cannot creat log file "
+                    + logFileName, ioe);
+                SlingLoggerFactory.internalFailure("Logging to the console",
+                    null);
+                output = new SlingLogWriter();
+            }
 
         } else {
 
             // fall back to console if no log file defined
-            appender = new ConsoleAppender<LoggingEvent>();
+            output = new SlingLogWriter();
 
         }
 
-        // finalize the appender setup
-        appender.setContext(loggerContext);
-        appender.setLayout(pl);
-        appender.start();
-
         // check for the log level setting in the web app properties
         String logLevel = context.getProperty(LOG_LEVEL);
+        if (logLevel == null || logLevel.length() == 0) {
+            logLevel = SlingLoggerLevel.INFO.toString();
+        } else {
+            logLevel = logLevel.toUpperCase();
+        }
 
-        // add the appender for the root logger
-        Logger rootLogger = loggerContext.getLogger(LoggerContext.ROOT_NAME);
-        rootLogger.addAppender(appender);
-        rootLogger.setLevel(Level.toLevel(logLevel, Level.WARN));
-
-        // do not go up the line if root is the prefixed-logger, otherwise if
-        // root is the real root, this has no effect
-        rootLogger.setAdditive(false);
+        // set the log appender message pattern
+        String messageFormatString = context.getProperty(LOG_PATTERN);
+        if (messageFormatString == null || messageFormatString.length() == 0) {
+            messageFormatString = LOG_PATTERN_DEFAULT;
+        }
+        MessageFormat messageFormat = new MessageFormat(messageFormatString);
+
+        // configure the logger factory now from the setup
+        SlingLoggerFactory loggerFactory = SlingLoggerFactory.getInstance();
+        loggerFactory.configure(logLevel, output, messageFormat);
     }
 
     protected static interface ConfigProperties {
         String getProperty(String name);
     }
+
 }

Added: incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriter.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriter.java?rev=648644&view=auto
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriter.java (added)
+++ incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriter.java Wed Apr 16 02:33:11 2008
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.log.slf4j;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+public class SlingLogFileWriter extends SlingLogWriter {
+
+    private static final long FACTOR_KB = 1024;
+    private static final long FACTOR_MB = 1024 * FACTOR_KB;
+    private static final long FACTOR_GB = 1024 * FACTOR_MB;
+    private static final long DEFAULT_MAX_SIZE = 10 * FACTOR_GB;
+    
+    private final File file;
+
+    private final String path;
+
+    private final long maxSize;
+
+    private final int maxNum;
+
+    public SlingLogFileWriter(String logFileName, int fileNum, String fileSize) throws IOException {
+        this(logFileName, fileNum, convertMaxSizeSpec(fileSize));
+    }
+    
+    public SlingLogFileWriter(String logFileName, int fileNum, long fileSize) throws IOException {
+        
+        // make sure the file is absolute and derive the path from there
+        File file = new File(logFileName);
+        if (!file.isAbsolute()) {
+            file = file.getAbsoluteFile();
+        }
+        
+        this.path = file.getAbsolutePath();
+        this.file = file;
+
+        this.maxNum = fileNum;
+        this.maxSize = fileSize;
+
+        setDelegatee(createFile());
+    }
+
+    @Override
+    public void flush() throws IOException {
+        super.flush();
+
+        checkRotate();
+    }
+    
+    private Writer createFile() throws IOException {
+        // ensure parent path of the file to create
+        file.getParentFile().mkdirs();
+
+        // open the file in append mode to not overwrite an existing
+        // log file from a previous instance running
+        return new OutputStreamWriter(new FileOutputStream(file, true));
+    }
+
+    private void checkRotate() throws IOException {
+        if (file.length() > maxSize) {
+            synchronized (lock) {
+
+                getDelegatee().close();
+
+                if (maxNum >= 0) {
+                    
+                    // remove oldest file
+                    File dstFile = new File(path + "." + maxNum);
+                    if (dstFile.exists()) {
+                        dstFile.delete();
+                    }
+
+                    // rename next files
+                    for (int i = maxNum - 1; i >= 0; i--) {
+                        File srcFile = new File(path + "." + i);
+                        if (srcFile.exists()) {
+                            srcFile.renameTo(dstFile);
+                        }
+                        dstFile = srcFile;
+                    }
+
+                    // rename youngest file
+                    file.renameTo(dstFile);
+                    
+                } else {
+                    
+                    // just remove the old file if we don't keep backups
+                    file.delete();
+                    
+                }
+                
+                // create new file
+                setDelegatee(createFile());
+            }
+        }
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public long getMaxSize() {
+        return maxSize;
+    }
+
+    public static long convertMaxSizeSpec(String maxSize) {
+        long factor;
+        int len = maxSize.length() - 1;
+
+        maxSize = maxSize.toUpperCase();
+
+        if (maxSize.endsWith("G")) {
+            factor = FACTOR_GB;
+        } else if (maxSize.endsWith("GB")) {
+            factor = FACTOR_GB;
+            len--;
+        } else if (maxSize.endsWith("M")) {
+            factor = FACTOR_MB;
+        } else if (maxSize.endsWith("MB")) {
+            factor = FACTOR_MB;
+            len--;
+        } else if (maxSize.endsWith("K")) {
+            factor = FACTOR_KB;
+        } else if (maxSize.endsWith("KB")) {
+            factor = FACTOR_KB;
+            len--;
+        } else {
+            factor = 1;
+            len = -1;
+        }
+
+        if (len > 0) {
+            maxSize = maxSize.substring(0, len);
+        }
+
+        try {
+            return factor * Long.parseLong(maxSize);
+        } catch (NumberFormatException nfe) {
+            return 10 * 1024 * 1024;
+        }
+    }
+
+    public int getMaxNum() {
+        return maxNum;
+    }
+
+}

Added: incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogWriter.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogWriter.java?rev=648644&view=auto
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogWriter.java (added)
+++ incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogWriter.java Wed Apr 16 02:33:11 2008
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.log.slf4j;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+public class SlingLogWriter extends Writer {
+
+    private String lineSeparator;
+
+    private Writer delegatee;
+
+    protected final Object lock = new Object();
+
+    public SlingLogWriter() {
+        delegatee = new OutputStreamWriter(System.out) {
+            @Override
+            public void close() {
+                // not really !!
+            }
+        };
+
+        lineSeparator = System.getProperty("line.separator");
+    }
+
+    protected void setDelegatee(Writer delegatee) {
+        synchronized (lock) {
+            this.delegatee = delegatee;
+        }
+    }
+
+    protected Writer getDelegatee() {
+        synchronized (lock) {
+            return delegatee;
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        synchronized (lock) {
+            if (delegatee != null) {
+                flush();
+                
+                delegatee.close();
+                delegatee = null;
+            }
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        synchronized (lock) {
+            if (delegatee != null) {
+                delegatee.flush();
+            }
+        }
+    }
+
+    @Override
+    public void write(int c) throws IOException {
+        synchronized (lock) {
+            if (delegatee != null) {
+                delegatee.write(c);
+            }
+        }
+    }
+
+    @Override
+    public void write(char[] cbuf) throws IOException {
+        synchronized (lock) {
+            if (delegatee != null) {
+                delegatee.write(cbuf);
+            }
+        }
+    }
+
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        synchronized (lock) {
+            if (delegatee != null) {
+                delegatee.write(cbuf, off, len);
+            }
+        }
+    }
+
+    @Override
+    public void write(String str) throws IOException {
+        synchronized (lock) {
+            if (delegatee != null) {
+                delegatee.write(str);
+            }
+        }
+    }
+
+    @Override
+    public void write(String str, int off, int len) throws IOException {
+        synchronized (lock) {
+            if (delegatee != null) {
+                delegatee.write(str, off, len);
+            }
+        }
+    }
+
+    public void writeln() throws IOException {
+        synchronized (lock) {
+            write(lineSeparator);
+            flush();
+        }
+    }
+}

Added: incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogger.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogger.java?rev=648644&view=auto
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogger.java (added)
+++ incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLogger.java Wed Apr 16 02:33:11 2008
@@ -0,0 +1,515 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.log.slf4j;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.FieldPosition;
+import java.text.MessageFormat;
+import java.util.Date;
+
+import org.slf4j.Logger;
+import org.slf4j.Marker;
+import org.slf4j.helpers.MessageFormatter;
+
+public class SlingLogger implements Logger {
+
+    private final String name;
+
+    private SlingLoggerLevel level;
+
+    private SlingLogWriter output;
+
+    private MessageFormat format;
+
+    public SlingLogger(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Configures this logger with the given log level, output and message
+     * format. None of these is allowed to be <code>null</code>.
+     */
+    void configure(SlingLoggerLevel level, SlingLogWriter output,
+            MessageFormat messageFormat) {
+        this.level = level;
+        this.output = output;
+        this.format = messageFormat;
+    }
+
+    // ---------- Actual Loger Entry writing -----------------------------------
+
+    private void log(Marker marker, SlingLoggerLevel level, String msg,
+            Throwable t) {
+        StringWriter writer = new StringWriter();
+
+        // create the formatted log line; use a local copy because the field
+        // may be exchanged while we are trying to use it
+        MessageFormat myFormat = format;
+        synchronized (myFormat) {
+            myFormat.format(new Object[] { new Date(), marker,
+                Thread.currentThread().getName(), getName(), level.toString(),
+                msg }, writer.getBuffer(), new FieldPosition(0));
+        }
+
+        // marker indicating whether a line terminator is to be written after
+        // the message: If a throwable is given, the stacktrace generator
+        // writes a final line terminator and hence we do need to do it
+        // ourselves
+        boolean needsEOL = true;
+
+        // append stacktrace if throwable is not null
+        if (t != null) {
+            writer.write(' ');
+            PrintWriter pw = new PrintWriter(writer);
+            t.printStackTrace(pw);
+            pw.flush();
+
+            // just flush the output, no EOL needed
+            needsEOL = false;
+        }
+
+        // use a local copy because the field may be exchanged while we are
+        // trying to use it
+        SlingLogWriter myOutput = output;
+        synchronized (myOutput) {
+            String message = writer.toString();
+            try {
+                myOutput.write(message);
+
+                // write line termination or flush, whatever is needed
+                if (needsEOL) {
+                    myOutput.writeln();
+                } else {
+                    myOutput.flush();
+                }
+
+            } catch (IOException ioe) {
+                SlingLoggerFactory.internalFailure("Failed logging message: " + message, ioe);
+            }
+        }
+    }
+
+    // ---------- Log Level support --------------------------------------------
+
+    public void setLogLevel(String levelString ) {
+        try {
+            // ensure upper case level name
+            levelString = levelString.toUpperCase();
+            
+            // try to convert to a SlingLoggerLevel instance,
+            // throws if the string is invalid
+            SlingLoggerLevel level = SlingLoggerLevel.valueOf(levelString);
+            
+            // finally set the level
+            this.setLogLevel(level);
+        } catch (Exception e) {
+            warn("Cannot set loglevel to " + level, e);
+        }
+    }
+
+    public void setLogLevel(SlingLoggerLevel level) {
+        this.level = level;
+    }
+
+    public SlingLoggerLevel getLogLevel() {
+        return level;
+    }
+
+    private boolean isLevel(SlingLoggerLevel reference) {
+        return level.compareTo(reference) <= 0;
+    }
+
+    // ---------- Logger interface ---------------------------------------------
+
+    public String getName() {
+        return name;
+    }
+
+    public void trace(String msg) {
+        if (isTraceEnabled()) {
+            log(null, SlingLoggerLevel.TRACE, msg, null);
+        }
+    }
+
+    public void trace(String format, Object arg) {
+        if (isTraceEnabled()) {
+            log(null, SlingLoggerLevel.TRACE, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void trace(String format, Object[] argArray) {
+        if (isTraceEnabled()) {
+            log(null, SlingLoggerLevel.TRACE, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void trace(String msg, Throwable t) {
+        if (isTraceEnabled()) {
+            log(null, SlingLoggerLevel.TRACE, msg, t);
+        }
+    }
+
+    public void trace(String format, Object arg1, Object arg2) {
+        if (isTraceEnabled()) {
+            log(null, SlingLoggerLevel.TRACE, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public void trace(Marker marker, String msg) {
+        if (isTraceEnabled(marker)) {
+            log(marker, SlingLoggerLevel.TRACE, msg, null);
+        }
+    }
+
+    public void trace(Marker marker, String format, Object arg) {
+        if (isTraceEnabled(marker)) {
+            log(marker, SlingLoggerLevel.TRACE, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void trace(Marker marker, String format, Object[] argArray) {
+        if (isTraceEnabled(marker)) {
+            log(marker, SlingLoggerLevel.TRACE, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void trace(Marker marker, String msg, Throwable t) {
+        if (isTraceEnabled(marker)) {
+            log(marker, SlingLoggerLevel.TRACE, msg, t);
+        }
+    }
+
+    public void trace(Marker marker, String format, Object arg1, Object arg2) {
+        if (isTraceEnabled(marker)) {
+            log(marker, SlingLoggerLevel.TRACE, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public void debug(String msg) {
+        if (isDebugEnabled()) {
+            log(null, SlingLoggerLevel.DEBUG, msg, null);
+        }
+    }
+
+    public void debug(String format, Object arg) {
+        if (isDebugEnabled()) {
+            log(null, SlingLoggerLevel.DEBUG, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void debug(String format, Object[] argArray) {
+        if (isDebugEnabled()) {
+            log(null, SlingLoggerLevel.DEBUG, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void debug(String msg, Throwable t) {
+        if (isDebugEnabled()) {
+            log(null, SlingLoggerLevel.DEBUG, msg, t);
+        }
+    }
+
+    public void debug(String format, Object arg1, Object arg2) {
+        if (isDebugEnabled()) {
+            log(null, SlingLoggerLevel.DEBUG, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public void debug(Marker marker, String msg) {
+        if (isDebugEnabled(marker)) {
+            log(marker, SlingLoggerLevel.DEBUG, msg, null);
+        }
+    }
+
+    public void debug(Marker marker, String format, Object arg) {
+        if (isDebugEnabled(marker)) {
+            log(marker, SlingLoggerLevel.DEBUG, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void debug(Marker marker, String format, Object[] argArray) {
+        if (isDebugEnabled(marker)) {
+            log(marker, SlingLoggerLevel.DEBUG, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void debug(Marker marker, String msg, Throwable t) {
+        if (isDebugEnabled(marker)) {
+            log(marker, SlingLoggerLevel.DEBUG, msg, t);
+        }
+    }
+
+    public void debug(Marker marker, String format, Object arg1, Object arg2) {
+        if (isDebugEnabled(marker)) {
+            log(marker, SlingLoggerLevel.DEBUG, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public void info(String msg) {
+        if (isInfoEnabled()) {
+            log(null, SlingLoggerLevel.INFO, msg, null);
+        }
+    }
+
+    public void info(String format, Object arg) {
+        if (isInfoEnabled()) {
+            log(null, SlingLoggerLevel.INFO, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void info(String format, Object[] argArray) {
+        if (isInfoEnabled()) {
+            log(null, SlingLoggerLevel.INFO, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void info(String msg, Throwable t) {
+        if (isInfoEnabled()) {
+            log(null, SlingLoggerLevel.INFO, msg, t);
+        }
+    }
+
+    public void info(String format, Object arg1, Object arg2) {
+        if (isInfoEnabled()) {
+            log(null, SlingLoggerLevel.INFO, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public void info(Marker marker, String msg) {
+        if (isInfoEnabled(marker)) {
+            log(marker, SlingLoggerLevel.INFO, msg, null);
+        }
+    }
+
+    public void info(Marker marker, String format, Object arg) {
+        if (isInfoEnabled(marker)) {
+            log(marker, SlingLoggerLevel.INFO, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void info(Marker marker, String format, Object[] argArray) {
+        if (isInfoEnabled(marker)) {
+            log(marker, SlingLoggerLevel.INFO, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void info(Marker marker, String msg, Throwable t) {
+        if (isInfoEnabled(marker)) {
+            log(marker, SlingLoggerLevel.INFO, msg, t);
+        }
+    }
+
+    public void info(Marker marker, String format, Object arg1, Object arg2) {
+        if (isInfoEnabled(marker)) {
+            log(marker, SlingLoggerLevel.INFO, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public void warn(String msg) {
+        if (isWarnEnabled()) {
+            log(null, SlingLoggerLevel.WARN, msg, null);
+        }
+    }
+
+    public void warn(String format, Object arg) {
+        if (isWarnEnabled()) {
+            log(null, SlingLoggerLevel.WARN, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void warn(String format, Object[] argArray) {
+        if (isWarnEnabled()) {
+            log(null, SlingLoggerLevel.WARN, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void warn(String msg, Throwable t) {
+        if (isWarnEnabled()) {
+            log(null, SlingLoggerLevel.WARN, msg, t);
+        }
+    }
+
+    public void warn(String format, Object arg1, Object arg2) {
+        if (isWarnEnabled()) {
+            log(null, SlingLoggerLevel.WARN, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public void warn(Marker marker, String msg) {
+        if (isWarnEnabled(marker)) {
+            log(marker, SlingLoggerLevel.WARN, msg, null);
+        }
+    }
+
+    public void warn(Marker marker, String format, Object arg) {
+        if (isWarnEnabled(marker)) {
+            log(marker, SlingLoggerLevel.WARN, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void warn(Marker marker, String format, Object[] argArray) {
+        if (isWarnEnabled(marker)) {
+            log(marker, SlingLoggerLevel.WARN, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void warn(Marker marker, String msg, Throwable t) {
+        if (isWarnEnabled(marker)) {
+            log(marker, SlingLoggerLevel.WARN, msg, t);
+        }
+    }
+
+    public void warn(Marker marker, String format, Object arg1, Object arg2) {
+        if (isWarnEnabled(marker)) {
+            log(marker, SlingLoggerLevel.WARN, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public void error(String msg) {
+        if (isErrorEnabled()) {
+            log(null, SlingLoggerLevel.ERROR, msg, null);
+        }
+    }
+
+    public void error(String format, Object arg) {
+        if (isErrorEnabled()) {
+            log(null, SlingLoggerLevel.ERROR, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void error(String format, Object[] argArray) {
+        if (isErrorEnabled()) {
+            log(null, SlingLoggerLevel.ERROR, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void error(String msg, Throwable t) {
+        if (isErrorEnabled()) {
+            log(null, SlingLoggerLevel.ERROR, msg, t);
+        }
+    }
+
+    public void error(String format, Object arg1, Object arg2) {
+        if (isErrorEnabled()) {
+            log(null, SlingLoggerLevel.ERROR, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public void error(Marker marker, String msg) {
+        if (isErrorEnabled(marker)) {
+            log(marker, SlingLoggerLevel.ERROR, msg, null);
+        }
+    }
+
+    public void error(Marker marker, String format, Object arg) {
+        if (isErrorEnabled(marker)) {
+            log(marker, SlingLoggerLevel.ERROR, MessageFormatter.format(format,
+                arg), null);
+        }
+    }
+
+    public void error(Marker marker, String format, Object[] argArray) {
+        if (isErrorEnabled(marker)) {
+            log(marker, SlingLoggerLevel.ERROR, MessageFormatter.arrayFormat(
+                format, argArray), null);
+        }
+    }
+
+    public void error(Marker marker, String msg, Throwable t) {
+        if (isErrorEnabled(marker)) {
+            log(marker, SlingLoggerLevel.ERROR, msg, t);
+        }
+    }
+
+    public void error(Marker marker, String format, Object arg1, Object arg2) {
+        if (isErrorEnabled(marker)) {
+            log(marker, SlingLoggerLevel.ERROR, MessageFormatter.format(format,
+                arg1, arg2), null);
+        }
+    }
+
+    public boolean isTraceEnabled() {
+        return isLevel(SlingLoggerLevel.TRACE);
+    }
+
+    public boolean isTraceEnabled(Marker marker) {
+        return isLevel(SlingLoggerLevel.TRACE);
+    }
+
+    public boolean isDebugEnabled() {
+        return isLevel(SlingLoggerLevel.DEBUG);
+    }
+
+    public boolean isDebugEnabled(Marker marker) {
+        return isLevel(SlingLoggerLevel.DEBUG);
+    }
+
+    public boolean isInfoEnabled() {
+        return isLevel(SlingLoggerLevel.INFO);
+    }
+
+    public boolean isInfoEnabled(Marker marker) {
+        return isLevel(SlingLoggerLevel.INFO);
+    }
+
+    public boolean isWarnEnabled() {
+        return isLevel(SlingLoggerLevel.WARN);
+    }
+
+    public boolean isWarnEnabled(Marker marker) {
+        return isLevel(SlingLoggerLevel.WARN);
+    }
+
+    public boolean isErrorEnabled() {
+        return isLevel(SlingLoggerLevel.ERROR);
+    }
+
+    public boolean isErrorEnabled(Marker marker) {
+        return isLevel(SlingLoggerLevel.ERROR);
+    }
+}

Added: incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerFactory.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerFactory.java?rev=648644&view=auto
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerFactory.java (added)
+++ incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerFactory.java Wed Apr 16 02:33:11 2008
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.log.slf4j;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.osgi.log.LogManager;
+import org.slf4j.ILoggerFactory;
+import org.slf4j.Logger;
+
+public final class SlingLoggerFactory implements ILoggerFactory {
+
+    private static final SlingLoggerFactory instance = new SlingLoggerFactory();
+
+    private final Map<String, SlingLogger> loggers = new HashMap<String, SlingLogger>();
+
+    /**
+     * The logger level currently configured to this factory. Before
+     * configuration, this is set to {@link SlingLoggerLevel#INFO}.
+     */
+    private SlingLoggerLevel level = SlingLoggerLevel.INFO;
+
+    /**
+     * The currently active log output. Before configuration, logging output is
+     * set to go to the console.
+     */
+    private SlingLogWriter output = new SlingLogWriter();
+
+    /**
+     * The currently active message format to generate the log message entries.
+     * Before configuration this is set to
+     * {@value LogManager#LOG_PATTERN_DEFAULT}.
+     */
+    private MessageFormat messageFormat = new MessageFormat(
+        LogManager.LOG_PATTERN_DEFAULT);
+
+    /**
+     * Returns the singleton instance of this class.
+     */
+    public static SlingLoggerFactory getInstance() {
+        return instance;
+    }
+
+    /**
+     * Logs a message an optional stack trace to error output. This method
+     * is used by the logging system in case of errors writing to the
+     * correct logging output.
+     */
+    public static void internalFailure(String message, Throwable t) {
+        System.err.println(message);
+        if (t != null) {
+            t.printStackTrace(System.err);
+        }
+    }
+    
+    // private constructor to prevent instantiation. This is a singleton class
+    private SlingLoggerFactory() {
+    }
+
+    // ---------- ILoggerFactory interface -------------------------------------
+
+    /**
+     * Returns a logger for the given name. If such a logger already exists the
+     * same logger is returned. Otherwise a new instance is created and
+     * configured with the current logging level, output and message format.
+     * 
+     * @param name The name of the logger to return
+     */
+    public Logger getLogger(String name) {
+        synchronized (loggers) {
+            SlingLogger logger = loggers.get(name);
+            if (logger == null) {
+                logger = createLogger(name);
+                loggers.put(name, logger);
+            }
+            return logger;
+        }
+    }
+
+    // ---------- Sling specific ILoggerFactory stuff --------------------------
+
+    /**
+     * Configures this factory and all existing loggers with the new log level,
+     * output and message format.
+     * 
+     * @param logLevel The log level to be set. If this is not a valid
+     *            {@link SlingLoggerLevel} value, the default <code>INFO</code>
+     *            is assumed.
+     * @param output The new ouptut channel
+     * @param messageFormat The new message format
+     */
+    public void configure(String logLevel, SlingLogWriter output,
+            MessageFormat messageFormat) {
+
+        // close the old output if existing
+        if (this.output != null) {
+            try {
+                this.output.close();
+            } catch (IOException ioe) {
+                internalFailure("Problem closing old output", ioe);
+            }
+        }
+
+        try {
+            this.level = SlingLoggerLevel.valueOf(logLevel);
+        } catch (Exception e) {
+            this.level = SlingLoggerLevel.INFO;
+        }
+
+        this.output = output;
+        this.messageFormat = messageFormat;
+
+        synchronized (loggers) {
+            for (SlingLogger logger : loggers.values()) {
+                logger.configure(level, output, messageFormat);
+            }
+        }
+    }
+
+    public void close() {
+        if (output != null) {
+            try {
+                output.close();
+            } catch (IOException ioe) {
+                internalFailure("Problem closing the output", ioe);
+            }
+        }
+    }
+    
+    public List<SlingLogger> getLoggerList() {
+        synchronized (loggers) {
+            return new ArrayList<SlingLogger>(loggers.values());
+        }
+    }
+
+    public SlingLogger getSlingLogger(String name) {
+        synchronized (loggers) {
+            return loggers.get(name);
+        }
+    }
+
+    private SlingLogger createLogger(String name) {
+        SlingLogger logger = new SlingLogger(name);
+        logger.configure(level, output, messageFormat);
+        return logger;
+    }
+    
+}

Added: incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerLevel.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerLevel.java?rev=648644&view=auto
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerLevel.java (added)
+++ incubator/sling/trunk/osgi/log/src/main/java/org/apache/sling/osgi/log/slf4j/SlingLoggerLevel.java Wed Apr 16 02:33:11 2008
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.log.slf4j;
+
+public enum SlingLoggerLevel {
+
+    TRACE,
+    DEBUG,
+    INFO,
+    WARN,
+    ERROR
+    
+}

Added: incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticLoggerBinder.java?rev=648644&view=auto
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticLoggerBinder.java (added)
+++ incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticLoggerBinder.java Wed Apr 16 02:33:11 2008
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.slf4j.impl;
+
+import org.apache.sling.osgi.log.slf4j.SlingLoggerFactory;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MarkerFactory;
+import org.slf4j.ILoggerFactory;
+import org.slf4j.IMarkerFactory;
+import org.slf4j.spi.LoggerFactoryBinder;
+
+/**
+ * This <code>StaticLoggerBinder</code> class returns the
+ * {@link SlingLoggerFactory} singleton instance as the SLF4J logger factory.
+ */
+public class StaticLoggerBinder implements LoggerFactoryBinder {
+
+    /**
+     * The unique instance of this class.
+     */
+    public static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
+
+    /**
+     * The ILoggerFactory instance returned by the {@link #getLoggerFactory}
+     * method should always be the same object
+     */
+    private final ILoggerFactory loggerFactory;
+
+    private StaticLoggerBinder() {
+        loggerFactory = SlingLoggerFactory.getInstance();
+    }
+
+    public ILoggerFactory getLoggerFactory() {
+        return loggerFactory;
+    }
+
+    public String getLoggerFactoryClassStr() {
+        return getLoggerFactory().getClass().getName();
+    }
+}
\ No newline at end of file

Added: incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticMarkerBinder.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticMarkerBinder.java?rev=648644&view=auto
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticMarkerBinder.java (added)
+++ incubator/sling/trunk/osgi/log/src/main/java/org/slf4j/impl/StaticMarkerBinder.java Wed Apr 16 02:33:11 2008
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.slf4j.impl;
+
+import org.slf4j.IMarkerFactory;
+import org.slf4j.helpers.BasicMarkerFactory;
+import org.slf4j.spi.MarkerFactoryBinder;
+
+/**
+ * This <code>StaticMarkerBinder</code> class returns an instance of the SLF4J
+ * <code>BasicMarkerFactory</code> as the marker factory.
+ */
+public class StaticMarkerBinder implements MarkerFactoryBinder {
+
+    /**
+     * The unique instance of this class.
+     */
+    public static final StaticMarkerBinder SINGLETON = new StaticMarkerBinder();
+
+    final IMarkerFactory markerFactory = new BasicMarkerFactory();
+
+    private StaticMarkerBinder() {
+    }
+
+    public IMarkerFactory getMarkerFactory() {
+        return markerFactory;
+    }
+
+    public String getMarkerFactoryClassStr() {
+        return getMarkerFactory().getClass().getName();
+    }
+
+}
\ No newline at end of file

Modified: incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=648644&r1=648643&r2=648644&view=diff
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.properties (original)
+++ incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.properties Wed Apr 16 02:33:11 2008
@@ -37,11 +37,17 @@
  reached the log file is copied and a new log file is created. This size \
  may be specified with size indicators KB, MB and GB. The default is 10MB.
 log.pattern.name = Message Pattern
-log.pattern.description = Message Pattern for the Pattern Layout. See \
- http://logback.qos.ch/manual/layouts.html#ClassicPatternLayout for more \
- information on the pattern.
-log.url.name = Configuration
-log.url.description = URL to a Logback configuration file. This URL must be \
- accessible to the Sling server, which is important in the case of file: URLs. \
- If this property is set and the configuration file succeeds configuring \
- Logback, the other configuration properties are actually ignored.
\ No newline at end of file
+log.pattern.description = Message Pattern for formatting the log messages. \
+ This is a java.util.MessageFormat pattern supporting up to five arguments: \
+ {0} The timestamp of type java.util.Date, {1} the log marker, {2} the name \
+ of the current thread, {3} the name of the logger, {4} the debug level and \
+ {5} the actual debug message. If the log call includes a Throwable, the \
+ stacktrace is just appended to the message.
+ 
+# Log File configuration is not supported at the moment
+# log.url.name = Configuration
+# log.url.description = URL to a configuration file. This URL must be \
+#  accessible to the Sling server, which is important in the case of file: URLs. \
+#  If this property is set and can successfully be used to configure logging, \
+#  the other configuration properties are actually ignored. Currently \
+#  this setting is ignored alltogether.
\ No newline at end of file

Modified: incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.xml
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.xml?rev=648644&r1=648643&r2=648644&view=diff
==============================================================================
--- incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.xml (original)
+++ incubator/sling/trunk/osgi/log/src/main/resources/OSGI-INF/metatype/metatype.xml Wed Apr 16 02:33:11 2008
@@ -20,7 +20,7 @@
 <metatype:MetaData
     xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0"
     localization="metatype">
-    <metatype:OCD id="org.apache.sling.osgi.log.LogbackManager"
+    <metatype:OCD id="org.apache.sling.osgi.log.LogManager"
         name="%log.name" description="%log.description">
         <metatype:AD id="org.apache.sling.osgi.log.level" type="String"
             default="info" name="%log.level.name"
@@ -40,14 +40,19 @@
             default="10mb" name="%log.file.size.name"
             description="%log.file.size.description" />
         <metatype:AD id="org.apache.sling.osgi.log.pattern" type="String"
-            default="%d{dd.MM.yyyy HH:mm:ss} *%-5p* %c{1}: %m%n"
+            default="{0\,date\,dd.MM.yyyy HH:mm:ss.SSS} *{4}* [{2}] {3} {5}"
             name="%log.pattern.name"
             description="%log.pattern.description" />
+            
+<!-- 
+        Log File configuration is not supported at the moment
         <metatype:AD id="org.apache.sling.osgi.log.url" type="String"
             default="" name="%log.url.name"
             description="%log.url.description" />
+-->
+
     </metatype:OCD>
-    <metatype:Designate pid="org.apache.sling.osgi.log.LogbackManager">
-        <metatype:Object ocdref="org.apache.sling.osgi.log.LogbackManager" />
+    <metatype:Designate pid="org.apache.sling.osgi.log.LogManager">
+        <metatype:Object ocdref="org.apache.sling.osgi.log.LogManager" />
     </metatype:Designate>
 </metatype:MetaData>

Added: incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriterTest.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriterTest.java?rev=648644&view=auto
==============================================================================
--- incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriterTest.java (added)
+++ incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLogFileWriterTest.java Wed Apr 16 02:33:11 2008
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.log.slf4j;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class SlingLogFileWriterTest extends TestCase {
+
+    private String base;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        
+        File baseFile = new File("target/" + System.currentTimeMillis() + "/" + getClass().getSimpleName());
+        baseFile.getParentFile().mkdirs();
+        base = baseFile.getAbsolutePath();
+    }
+    
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testNoRotateSize() throws IOException {
+        
+        SlingLogFileWriter slfw = new SlingLogFileWriter(base, -1, 10);
+        
+        // only base file should exist with size 0 (for now)
+        File test = new File(base);
+        assertTrue(test.exists() && test.length() == 0);
+        
+        File test0 = new File(base + ".0");
+        assertFalse(test0.exists());
+        File testn1 = new File(base + ".-1");
+        assertFalse(testn1.exists());
+        
+        // write some bytes and ensure size
+        slfw.write("012345");
+        slfw.writeln();
+        assertTrue(test.exists() && test.length() > 0);
+        assertFalse(test0.exists());
+        assertFalse(testn1.exists());
+        
+        // write some more, ensuring rotation does happen
+        slfw.write("012345");
+        slfw.writeln();
+        assertTrue(test.exists() && test.length() == 0);
+        assertFalse(test0.exists());
+        assertFalse(testn1.exists());
+    }
+
+    public void testRotate0Size() throws IOException {
+        
+        SlingLogFileWriter slfw = new SlingLogFileWriter(base, 0, 10);
+        
+        // only base file should exist with size 0 (for now)
+        File test = new File(base);
+        assertTrue(test.exists() && test.length() == 0);
+        
+        File test0 = new File(base + ".0");
+        assertFalse(test0.exists());
+        File test1 = new File(base + ".1");
+        assertFalse(test1.exists());
+        File testn1 = new File(base + ".-1");
+        assertFalse(testn1.exists());
+        
+        // write some bytes and ensure size
+        slfw.write("012345");
+        slfw.writeln();
+        assertTrue(test.exists() && test.length() > 0);
+        assertFalse(test0.exists());
+        assertFalse(testn1.exists());
+        
+        // write some more, ensuring rotation does happen
+        slfw.write("012345");
+        slfw.writeln();
+        assertTrue(test.exists() && test.length() == 0);
+        assertTrue(test0.exists());
+        assertFalse(test1.exists());
+        assertFalse(testn1.exists());
+    }
+    
+    public void testRotate1Size() throws IOException {
+
+        SlingLogFileWriter slfw = new SlingLogFileWriter(base, 1, 10);
+        
+        // only base file should exist with size 0 (for now)
+        File test = new File(base);
+        assertTrue(test.exists() && test.length() == 0);
+        
+        File test0 = new File(base + ".0");
+        assertFalse(test0.exists());
+        File test1 = new File(base + ".1");
+        assertFalse(test1.exists());
+        File testn1 = new File(base + ".-1");
+        assertFalse(testn1.exists());
+        
+        // write some bytes and ensure size
+        slfw.write("012345");
+        slfw.writeln();
+        assertTrue(test.exists() && test.length() > 0);
+        assertFalse(test0.exists());
+        assertFalse(testn1.exists());
+        
+        // write some more, ensuring rotation does happen
+        slfw.write("012345");
+        slfw.writeln();
+        assertTrue(test.exists() && test.length() == 0);
+        assertTrue(test0.exists());
+        assertFalse(test1.exists());
+        assertFalse(testn1.exists());
+        
+        // write bytes to rotate in onw fell swoop
+        slfw.write("0123456789 - more");
+        slfw.writeln();
+        assertTrue(test.exists() && test.length() == 0);
+        assertTrue(test0.exists());
+        assertTrue(test1.exists());
+        assertFalse(testn1.exists());
+    }
+    
+    public void testMaxSizeConversion() {
+        assertEquals(1, SlingLogFileWriter.convertMaxSizeSpec("1"));
+        
+        // kilo
+        assertEquals(1*1024, SlingLogFileWriter.convertMaxSizeSpec("1K"));
+        assertEquals(1*1024, SlingLogFileWriter.convertMaxSizeSpec("1k"));
+        assertEquals(1*1024, SlingLogFileWriter.convertMaxSizeSpec("1KB"));
+        assertEquals(1*1024, SlingLogFileWriter.convertMaxSizeSpec("1kb"));
+        
+        // mega
+        assertEquals(1*1024*1024, SlingLogFileWriter.convertMaxSizeSpec("1M"));
+        assertEquals(1*1024*1024, SlingLogFileWriter.convertMaxSizeSpec("1m"));
+        assertEquals(1*1024*1024, SlingLogFileWriter.convertMaxSizeSpec("1MB"));
+        assertEquals(1*1024*1024, SlingLogFileWriter.convertMaxSizeSpec("1mb"));
+        
+        // giga
+        assertEquals(1*1024*1024*1024, SlingLogFileWriter.convertMaxSizeSpec("1G"));
+        assertEquals(1*1024*1024*1024, SlingLogFileWriter.convertMaxSizeSpec("1g"));
+        assertEquals(1*1024*1024*1024, SlingLogFileWriter.convertMaxSizeSpec("1GB"));
+        assertEquals(1*1024*1024*1024, SlingLogFileWriter.convertMaxSizeSpec("1gb"));
+    }
+}

Added: incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLoggerTest.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLoggerTest.java?rev=648644&view=auto
==============================================================================
--- incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLoggerTest.java (added)
+++ incubator/sling/trunk/osgi/log/src/test/java/org/apache/sling/osgi/log/slf4j/SlingLoggerTest.java Wed Apr 16 02:33:11 2008
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.log.slf4j;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.MessageFormat;
+
+import junit.framework.TestCase;
+
+public class SlingLoggerTest extends TestCase {
+
+    private static final String LOGGER_NAME = "test.log";
+
+    private SlingLogWriter output = new SlingLogWriter() {
+        public void writeln() throws IOException {
+            // just flush, no end of line
+            flush();
+        }
+    };
+
+    private MessageFormat messageOnly = new MessageFormat("{5}");
+
+    private SlingLogger logger;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        logger = new SlingLogger(LOGGER_NAME);
+        logger.configure(SlingLoggerLevel.DEBUG, output, messageOnly);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        output.close();
+        super.tearDown();
+    }
+
+    public void testSetLogLevel() {
+
+        // prevent real output, set output delegatee to null
+        try {
+            output.getDelegatee().close();
+        } catch (IOException ignore) {
+        }
+        output.setDelegatee(null);
+
+        // initial assertion
+        logger.setLogLevel(SlingLoggerLevel.DEBUG);
+        assertEquals(SlingLoggerLevel.DEBUG, logger.getLogLevel());
+
+        // valid as is
+        logger.setLogLevel("INFO");
+        assertEquals(SlingLoggerLevel.INFO, logger.getLogLevel());
+
+        // valid internal conversion to upper case
+        logger.setLogLevel("warn");
+        assertEquals(SlingLoggerLevel.WARN, logger.getLogLevel());
+        logger.setLogLevel("ErrOr");
+        assertEquals(SlingLoggerLevel.ERROR, logger.getLogLevel());
+
+        // reset log level to debug
+        logger.setLogLevel(SlingLoggerLevel.DEBUG);
+        assertEquals(SlingLoggerLevel.DEBUG, logger.getLogLevel());
+
+        // invalid, last level is still set
+        logger.setLogLevel((String) null);
+        assertEquals(SlingLoggerLevel.DEBUG, logger.getLogLevel());
+
+        // invalid, last level is still set
+        logger.setLogLevel("");
+        assertEquals(SlingLoggerLevel.DEBUG, logger.getLogLevel());
+
+        // invalid, last level is still set
+        logger.setLogLevel("gurk");
+        assertEquals(SlingLoggerLevel.DEBUG, logger.getLogLevel());
+    }
+
+    public void testCheckLogLevelTrace() {
+        // initial assertion
+        logger.setLogLevel(SlingLoggerLevel.TRACE);
+        assertEquals(SlingLoggerLevel.TRACE, logger.getLogLevel());
+
+        // ensure logging disabled
+        // none for trace
+
+        // ensure logging enabled
+        assertTrue(logger.isTraceEnabled());
+        assertTrue(logger.isDebugEnabled());
+        assertTrue(logger.isInfoEnabled());
+        assertTrue(logger.isWarnEnabled());
+        assertTrue(logger.isErrorEnabled());
+    }
+
+    public void testCheckLogLevelDebug() {
+        // initial assertion
+        logger.setLogLevel(SlingLoggerLevel.DEBUG);
+        assertEquals(SlingLoggerLevel.DEBUG, logger.getLogLevel());
+
+        // ensure logging disabled
+        assertFalse(logger.isTraceEnabled());
+
+        // ensure logging enabled
+        assertTrue(logger.isDebugEnabled());
+        assertTrue(logger.isInfoEnabled());
+        assertTrue(logger.isWarnEnabled());
+        assertTrue(logger.isErrorEnabled());
+    }
+
+    public void testCheckLogLevelInfo() {
+        // initial assertion
+        logger.setLogLevel(SlingLoggerLevel.INFO);
+        assertEquals(SlingLoggerLevel.INFO, logger.getLogLevel());
+
+        // ensure logging disabled
+        assertFalse(logger.isTraceEnabled());
+        assertFalse(logger.isDebugEnabled());
+
+        // ensure logging enabled
+        assertTrue(logger.isInfoEnabled());
+        assertTrue(logger.isWarnEnabled());
+        assertTrue(logger.isErrorEnabled());
+    }
+
+    public void testCheckLogLevelWarn() {
+        // initial assertion
+        logger.setLogLevel(SlingLoggerLevel.WARN);
+        assertEquals(SlingLoggerLevel.WARN, logger.getLogLevel());
+
+        // ensure logging disabled
+        assertFalse(logger.isTraceEnabled());
+        assertFalse(logger.isDebugEnabled());
+        assertFalse(logger.isInfoEnabled());
+
+        // ensure logging enabled
+        assertTrue(logger.isWarnEnabled());
+        assertTrue(logger.isErrorEnabled());
+    }
+
+    public void testCheckLogLevelError() {
+        // initial assertion
+        logger.setLogLevel(SlingLoggerLevel.ERROR);
+        assertEquals(SlingLoggerLevel.ERROR, logger.getLogLevel());
+
+        // ensure logging disabled
+        assertFalse(logger.isTraceEnabled());
+        assertFalse(logger.isDebugEnabled());
+        assertFalse(logger.isInfoEnabled());
+        assertFalse(logger.isWarnEnabled());
+
+        // ensure logging enabled
+        assertTrue(logger.isErrorEnabled());
+    }
+
+    public void testFormat() {
+        StringWriter w = new StringWriter();
+        output.setDelegatee(w);
+
+        // a single message
+        logger.configure(SlingLoggerLevel.DEBUG, output, messageOnly);
+
+        String message = "This is a message";
+        logger.warn(message);
+        assertEquals(message, w.toString());
+
+        // reset output buffer and format with logger name and message
+        w.getBuffer().delete(0, w.getBuffer().length());
+        logger.configure(SlingLoggerLevel.DEBUG, output, new MessageFormat(
+            "{3}|{5}"));
+
+        logger.warn(message);
+        assertEquals(logger.getName() + "|" + message, w.toString());
+
+        // reset output buffer and format with logger name, level, thread and
+        // message
+        w.getBuffer().delete(0, w.getBuffer().length());
+        logger.configure(SlingLoggerLevel.DEBUG, output, new MessageFormat(
+            "{2}|{3}|{4}|{5}"));
+        logger.warn(message);
+        assertEquals(Thread.currentThread().getName() + "|" + logger.getName()
+            + "|" + SlingLoggerLevel.WARN + "|" + message, w.toString());
+    }
+}