Commits

Sebastian Sdorra committed 5ef2729

added a mechanism to change the default logger implementation

Comments (0)

Files changed (6)

src/main/java/com/aragost/javahg/log/JULLogger.java

+package com.aragost.javahg.log;
+
+import java.util.logging.Level;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * This simulates the Logger class from slf4j.
+ * <p>
+ * Only the methods that is actually used by JavaHg is implemented,
+ * but others will be added as needed.
+ * <p>
+ * Implementation note: In general for log level abc there is an
+ * <code>void abc(String msg)</code> and
+ * <code>void abc(String msg, Object[] args)</code>. The first simply
+ * writes the message to the backend with no formatting, the second
+ * will do a formatting similar to slf4j. The first is strictly not
+ * needed, but the consequence would be that for even simple log
+ * messages a temp array would be created for the varargs.
+ * 
+ */
+public class JULLogger implements Logger {
+
+    private final java.util.logging.Logger julLogger;
+
+    public JULLogger(String name) {
+        this.julLogger = java.util.logging.Logger.getLogger(name);
+    }
+
+    public void debug(String msg) {
+        this.julLogger.fine(msg);
+    }
+
+    public void debug(String msg, Object... args) {
+        if (isDebugEnabled()) {
+            this.julLogger.fine(format(msg, args));
+        }
+    }
+    
+    public void debug(String msg, Throwable thrown)
+    {
+      logException(Level.FINE, msg, thrown);
+    }
+
+    public void info(String msg) {
+        this.julLogger.info(msg);
+    }
+
+    public void info(String msg, Object... args) {
+        if (isInfoEnabled()) {
+            this.julLogger.info(format(msg, args));
+        }
+    }
+
+    public void info(String msg, Throwable thrown)
+    {
+      logException(Level.INFO, msg, thrown);
+    }
+
+    public void warn(String msg)
+    {
+      this.julLogger.warning(msg);
+    }
+    
+    public void warn(String msg, Object... args) {
+        this.julLogger.warning(format(msg, args));
+    }
+
+    public void warn(String msg, Throwable thrown)
+    {
+      logException(Level.WARNING, msg, thrown);
+    }
+
+    public void error(String msg)
+    {
+      this.julLogger.severe(msg);
+    }
+
+    public void error(String msg, Object... args) {
+        this.julLogger.severe(format(msg, args));
+    }
+
+    public void error(String msg, Throwable thrown) {
+        logException(Level.SEVERE, msg, thrown);
+    }
+    
+    public boolean isDebugEnabled() {
+        return this.julLogger.isLoggable(Level.FINE);
+    }
+
+    public boolean isInfoEnabled() {
+        return this.julLogger.isLoggable(Level.INFO);
+    }
+
+    public boolean isWarnEnabled()
+    {
+      return this.julLogger.isLoggable(Level.WARNING);
+    }
+
+    public boolean isErrorEnabled()
+    {
+      return this.julLogger.isLoggable(Level.SEVERE);
+    }
+    
+
+    /**
+     * Simulate the slf4j formatting of messages. This does not have
+     * all the features of slf4j, it is not possible to escape {} in
+     * the message. It will always be interpreted as an anchore.
+     * <p>
+     * If there is too few args compared to anchors in the format then
+     * the method fails with IndexOutOfBoundException
+     * 
+     * @param format
+     * @param args
+     * @return
+     */
+    @VisibleForTesting
+    static String format(String format, Object[] args) {
+        int length = format.length();
+        StringBuilder tgt = new StringBuilder(length);
+        int prevPos = 0;
+        int argIndex = 0;
+        while (prevPos < length) {
+            int pos = format.indexOf("{}", prevPos);
+            if (pos >= 0) {
+                Object arg = args[argIndex++];
+                tgt.append(format.substring(prevPos, pos));
+                tgt.append(arg == null ? "" : arg.toString());
+                prevPos = pos + 2;
+            } else {
+                tgt.append(format.substring(prevPos));
+                prevPos = length;
+            }
+        }
+        return tgt.toString();
+    }
+
+    private void logException(Level level, String msg, Throwable thrown) {
+        this.julLogger.log(level, msg, thrown);
+    }
+}

src/main/java/com/aragost/javahg/log/JULLoggerFactory.java

+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.aragost.javahg.log;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class JULLoggerFactory extends LoggerFactory
+{
+
+  @Override
+  protected Logger getLoggerInstance(Class<?> cls)
+  {
+    return new JULLogger(cls.getName());
+  }
+  
+}

src/main/java/com/aragost/javahg/log/Logger.java

 package com.aragost.javahg.log;
 
-import java.util.logging.Level;
-
-import com.google.common.annotations.VisibleForTesting;
-
 /**
- * This simulates the Logger class from slf4j.
- * <p>
- * Only the methods that is actually used by JavaHg is implemented,
- * but others will be added as needed.
- * <p>
- * Implementation note: In general for log level abc there is an
- * <code>void abc(String msg)</code> and
- * <code>void abc(String msg, Object[] args)</code>. The first simply
- * writes the message to the backend with no formatting, the second
- * will do a formatting similar to slf4j. The first is strictly not
- * needed, but the consequence would be that for even simple log
- * messages a temp array would be created for the varargs.
+ * General interface for logging. This interface is used by each JavaHG class
+ * for logging. A implementation of the logger interface can be retrieved
+ * by {@link LoggerFactory#getLogger(java.lang.Class)}.
  * 
  */
-public class Logger {
-
-    private final java.util.logging.Logger julLogger;
-
-    public Logger(String name) {
-        this.julLogger = java.util.logging.Logger.getLogger(name);
-    }
+public interface Logger {
 
     /**
      * Logs a debugging message - detailed debugging information that can be
      * @param msg
      *            The message to log.
      */
-    public void debug(String msg) {
-        this.julLogger.fine(msg);
-    }
+    public void debug(String msg);
 
     /**
      * Logs a debugging message - detailed debugging information that can be
      * @param msg
      *            The message to log.
      */
-    public void debug(String msg, Object... args) {
-        if (isDebugEnabled()) {
-            this.julLogger.fine(format(msg, args));
-        }
-    }
+    public void debug(String msg, Object... args);
+    
+    public void debug(String msg, Throwable thrown);
 
     /**
      * Logs an informational message - information about application progress,
      * @param message
      *            The message to log.
      */
-    public void info(String msg) {
-        this.julLogger.info(msg);
-    }
+    public void info(String msg);
 
-    public void info(String msg, Object... args) {
-        if (isInfoEnabled()) {
-            this.julLogger.info(format(msg, args));
-        }
-    }
+    public void info(String msg, Object... args);
+    
+    public void info(String msg, Throwable thrown);
 
-    public void warn(String msg, Object... args) {
-        this.julLogger.warning(format(msg, args));
-    }
+    public void warn(String msg);
+    
+    public void warn(String msg, Object... args);
+    
+    public void warn(String msg, Throwable thrown);
+    
+    public void error(String msg);
 
-    public void error(String msg, Object... args) {
-        this.julLogger.severe(format(msg, args));
-    }
+    public void error(String msg, Object... args);
 
-    public void error(String msg, Throwable thrown) {
-        logException(Level.SEVERE, msg, thrown);
-    }
+    public void error(String msg, Throwable thrown);
 
-    public boolean isInfoEnabled() {
-        return this.julLogger.isLoggable(Level.INFO);
-    }
+    public boolean isInfoEnabled();
 
-    public boolean isDebugEnabled() {
-        return this.julLogger.isLoggable(Level.FINE);
-    }
-
-    /**
-     * Simulate the slf4j formatting of messages. This does not have
-     * all the features of slf4j, it is not possible to escape {} in
-     * the message. It will always be interpreted as an anchore.
-     * <p>
-     * If there is too few args compared to anchors in the format then
-     * the method fails with IndexOutOfBoundException
-     * 
-     * @param format
-     * @param args
-     * @return
-     */
-    @VisibleForTesting
-    static String format(String format, Object[] args) {
-        int length = format.length();
-        StringBuilder tgt = new StringBuilder(length);
-        int prevPos = 0;
-        int argIndex = 0;
-        while (prevPos < length) {
-            int pos = format.indexOf("{}", prevPos);
-            if (pos >= 0) {
-                Object arg = args[argIndex++];
-                tgt.append(format.substring(prevPos, pos));
-                tgt.append(arg == null ? "" : arg.toString());
-                prevPos = pos + 2;
-            } else {
-                tgt.append(format.substring(prevPos));
-                prevPos = length;
-            }
-        }
-        return tgt.toString();
-    }
-
-    private void logException(Level level, String msg, Throwable thrown) {
-        this.julLogger.log(level, msg, thrown);
-    }
+    public boolean isDebugEnabled();
+    
+    public boolean isWarnEnabled();
+    
+    public boolean isErrorEnabled();
 }

src/main/java/com/aragost/javahg/log/LoggerFactory.java

 package com.aragost.javahg.log;
 
+import java.util.ServiceLoader;
+
 /**
- * Factory class to retrieve a {@link Logger} instance.
+ * Factory class to retrieve a {@link Logger} instance. The LoggerFactory 
+ * searches a implementation with the use of {@link ServiceLoader}, if no
+ * implementation could be found it uses the default implementation 
+ * {@link JULLoggerFactory}.
  */
-public class LoggerFactory {
+public abstract class LoggerFactory {
 
+    private static LoggerFactory instance;
+  
+    static {
+        try 
+        {
+            ServiceLoader<LoggerFactory> loader = ServiceLoader.load(LoggerFactory.class);
+            instance = loader.iterator().next();
+        } 
+        catch (Exception ex)
+        {
+          // do nothing
+        }
+        if ( instance == null ){
+            instance = new JULLoggerFactory();
+        }
+    }
+  
     /**
      * Return a logger for the class
      * 
      * @return
      */
     public static Logger getLogger(Class<?> cls) {
-        return new Logger(cls.getName());
+        return instance.getLoggerInstance(cls);
     }
+    
+    protected abstract Logger getLoggerInstance(Class<?> cls);
 
-}
+}

src/test/java/com/aragost/javahg/log/JULLoggerTest.java

+package com.aragost.javahg.log;
+
+import static com.aragost.javahg.log.JULLogger.format;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JULLoggerTest {
+    
+    @Test
+    public void testFormat() {
+        Assert.assertEquals("", format("", new Object[0]));
+        Assert.assertEquals("abc", format("abc", new Object[] { null }));
+        Assert.assertEquals("ab", format("{}{}{}", new Object[] { "a", null, "b" }));
+        Assert.assertEquals("a1b2c3d", format("a{}b{}c{}d", new Object[] { 1,2,3,4,5,6 }));
+    }
+
+}

src/test/java/com/aragost/javahg/log/LoggerTest.java

-package com.aragost.javahg.log;
-
-import static com.aragost.javahg.log.Logger.format;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class LoggerTest {
-    
-    @Test
-    public void testFormat() {
-        Assert.assertEquals("", format("", new Object[0]));
-        Assert.assertEquals("abc", format("abc", new Object[] { null }));
-        Assert.assertEquals("ab", format("{}{}{}", new Object[] { "a", null, "b" }));
-        Assert.assertEquals("a1b2c3d", format("a{}b{}c{}d", new Object[] { 1,2,3,4,5,6 }));
-    }
-
-}