Improve test reliability
Reduce the complexity of the Logger code

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1458280 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/runtime/core-it/src/it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/src/it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
index df11138..f0fe02f 100644
--- a/ipojo/runtime/core-it/src/it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
+++ b/ipojo/runtime/core-it/src/it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -38,8 +38,10 @@
 import org.ops4j.pax.exam.spi.reactors.PerClass;
 import org.ops4j.pax.tinybundles.core.TinyBundle;
 import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
 import org.ow2.chameleon.testing.helpers.IPOJOHelper;
 import org.ow2.chameleon.testing.helpers.OSGiHelper;
 import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
@@ -94,6 +96,8 @@
         }
         String version = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VERSION);
         System.out.println("OSGi Framework : " + vendor + " - " + version);
+
+        waitForStability(bc);
     }
 
     @After
@@ -157,5 +161,78 @@
         }
     }
 
+    /**
+     * Waits for stability:
+     * <ul>
+     * <li>all bundles are activated
+     * <li>service count is stable
+     * </ul>
+     * If the stability can't be reached after a specified time,
+     * the method throws a {@link IllegalStateException}.
+     * @param context the bundle context
+     * @throws IllegalStateException when the stability can't be reach after a several attempts.
+     */
+    private void waitForStability(BundleContext context) throws IllegalStateException {
+        // Wait for bundle initialization.
+        boolean bundleStability = getBundleStability(context);
+        int count = 0;
+        while (!bundleStability && count < 500) {
+            try {
+                Thread.sleep(5);
+            } catch (InterruptedException e) {
+                // Interrupted
+            }
+            count++;
+            bundleStability = getBundleStability(context);
+        }
+
+        if (count == 500) {
+            for (Bundle bundle : bc.getBundles()) {
+                System.out.println("Bundle " + bundle.getSymbolicName() + " - " + bundle.getState());
+            }
+            System.err.println("Bundle stability isn't reached after 500 tries");
+            throw new IllegalStateException("Cannot reach the bundle stability");
+        }
+
+        boolean serviceStability = false;
+        count = 0;
+        int count1 = 0;
+        int count2 = 0;
+        while (! serviceStability && count < 500) {
+            try {
+                ServiceReference[] refs = context.getServiceReferences((String) null, null);
+                count1 = refs.length;
+                Thread.sleep(500);
+                refs = context.getServiceReferences((String) null, null);
+                count2 = refs.length;
+                serviceStability = count1 == count2;
+            } catch (Exception e) {
+                System.err.println(e);
+                serviceStability = false;
+                // Nothing to do, while recheck the condition
+            }
+            count++;
+        }
+
+        if (count == 500) {
+            System.err.println("Service stability isn't reached after 500 tries (" + count1 + " != " + count2);
+            throw new IllegalStateException("Cannot reach the service stability");
+        }
+    }
+
+    /**
+     * Are bundle stables.
+     * @param bc the bundle context
+     * @return <code>true</code> if every bundles are activated.
+     */
+    private boolean getBundleStability(BundleContext bc) {
+        boolean stability = true;
+        Bundle[] bundles = bc.getBundles();
+        for (int i = 0; i < bundles.length; i++) {
+            stability = stability && (bundles[i].getState() == Bundle.ACTIVE);
+        }
+        return stability;
+    }
+
 
 }
diff --git a/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
index 6bc2c21..56b670e 100644
--- a/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
+++ b/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -37,8 +37,10 @@
 import org.ops4j.pax.exam.spi.reactors.PerMethod;
 import org.ops4j.pax.tinybundles.core.TinyBundle;
 import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
 import org.ow2.chameleon.testing.helpers.IPOJOHelper;
 import org.ow2.chameleon.testing.helpers.OSGiHelper;
 import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
@@ -132,6 +134,8 @@
         }
         String version = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VERSION);
         System.out.println("OSGi Framework : " + vendor + " - " + version);
+
+        waitForStability(bc);
     }
 
     @After
@@ -212,5 +216,78 @@
         fail("Assertion failed : " + s);
     }
 
+    /**
+     * Waits for stability:
+     * <ul>
+     * <li>all bundles are activated
+     * <li>service count is stable
+     * </ul>
+     * If the stability can't be reached after a specified time,
+     * the method throws a {@link IllegalStateException}.
+     * @param context the bundle context
+     * @throws IllegalStateException when the stability can't be reach after a several attempts.
+     */
+    private void waitForStability(BundleContext context) throws IllegalStateException {
+        // Wait for bundle initialization.
+        boolean bundleStability = getBundleStability(context);
+        int count = 0;
+        while (!bundleStability && count < 500) {
+            try {
+                Thread.sleep(5);
+            } catch (InterruptedException e) {
+                // Interrupted
+            }
+            count++;
+            bundleStability = getBundleStability(context);
+        }
+
+        if (count == 500) {
+            for (Bundle bundle : bc.getBundles()) {
+                System.out.println("Bundle " + bundle.getSymbolicName() + " - " + bundle.getState());
+            }
+            System.err.println("Bundle stability isn't reached after 500 tries");
+            throw new IllegalStateException("Cannot reach the bundle stability");
+        }
+
+        boolean serviceStability = false;
+        count = 0;
+        int count1 = 0;
+        int count2 = 0;
+        while (! serviceStability && count < 500) {
+            try {
+                ServiceReference[] refs = context.getServiceReferences((String) null, null);
+                count1 = refs.length;
+                Thread.sleep(500);
+                refs = context.getServiceReferences((String) null, null);
+                count2 = refs.length;
+                serviceStability = count1 == count2;
+            } catch (Exception e) {
+                System.err.println(e);
+                serviceStability = false;
+                // Nothing to do, while recheck the condition
+            }
+            count++;
+        }
+
+        if (count == 500) {
+            System.err.println("Service stability isn't reached after 500 tries (" + count1 + " != " + count2);
+            throw new IllegalStateException("Cannot reach the service stability");
+        }
+    }
+
+    /**
+     * Are bundle stables.
+     * @param bc the bundle context
+     * @return <code>true</code> if every bundles are activated.
+     */
+    private boolean getBundleStability(BundleContext bc) {
+        boolean stability = true;
+        Bundle[] bundles = bc.getBundles();
+        for (int i = 0; i < bundles.length; i++) {
+            stability = stability && (bundles[i].getState() == Bundle.ACTIVE);
+        }
+        return stability;
+    }
+
 
 }
diff --git a/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBNDManifestLoggerInfo.java b/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBNDManifestLoggerInfo.java
index 791a4dd..0e9c61f 100644
--- a/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBNDManifestLoggerInfo.java
+++ b/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBNDManifestLoggerInfo.java
@@ -19,6 +19,10 @@
 
 package org.apache.felix.ipojo.runtime.core;
 
+import org.apache.commons.io.FileUtils;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
 import org.apache.felix.ipojo.runtime.core.components.MyComponent;
 import org.apache.felix.ipojo.runtime.core.services.MyService;
 import org.junit.Assert;
@@ -29,6 +33,7 @@
 import org.ops4j.pax.exam.OptionUtils;
 import org.ops4j.pax.tinybundles.core.TinyBundles;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.log.LogEntry;
 import org.osgi.service.log.LogReaderService;
 import org.osgi.service.log.LogService;
@@ -77,7 +82,7 @@
                 streamBundle(
                         TinyBundles.bundle()
                                 .add(MyComponent.class)
-                                .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+                                .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent-WTF")
                                 .set("IPOJO-log-level", "info")
                                 .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/component.xml")))
                 )
@@ -86,6 +91,7 @@
 
     @Test
     public void testMessages() throws InterruptedException {
+        osgiHelper.waitForService(Architecture.class, "(architecture.instance=org.apache.felix.ipojo.runtime.core.components.MyComponent-0)", 10000);
         List<String> messages = getMessages(log.getLog());
         Assert.assertTrue(messages.contains("Ready"));
         Assert.assertTrue(messages.contains("[INFO] org.apache.felix.ipojo.runtime.core.components.MyComponent : Instance org.apache.felix.ipojo.runtime.core.components.MyComponent-0 from factory org.apache.felix.ipojo.runtime.core.components.MyComponent created"));
diff --git a/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/SystemLoggerWarningTest.java b/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSystemLoggerWarning.java
similarity index 98%
rename from ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/SystemLoggerWarningTest.java
rename to ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSystemLoggerWarning.java
index 29b3d4d..0815b4b 100644
--- a/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/SystemLoggerWarningTest.java
+++ b/ipojo/runtime/core-it/src/it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSystemLoggerWarning.java
@@ -43,7 +43,7 @@
 import static org.ops4j.pax.exam.CoreOptions.*;
 import static org.ops4j.pax.exam.MavenUtils.asInProject;
 
-public class SystemLoggerWarningTest extends Common {
+public class TestSystemLoggerWarning extends Common {
 
     private LogReaderService log;
 
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Log.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Log.java
index 5730053..6bbfe28 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Log.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Log.java
@@ -43,4 +43,5 @@
     void log(int level, String msg);
 
     void log(int level, String msg, Throwable exception);
+
 }
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Logger.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
index b7d6760..1713e2d 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
@@ -38,61 +38,46 @@
      * The iPOJO default log level property.
      */
     public static final String IPOJO_LOG_LEVEL_PROP = "ipojo.log.level";
-
     /**
      * iPOJO log level manifest header.
      * The uppercase 'I' is important as BND removes all headers that do not
      * start with an uppercase are not added to the bundle.
      * Use an upper case to support bnd.
      */
-    public static final String IPOJO_LOG_LEVEL_HEADER = "Ipojo-log-level";
-
+    public static final String IPOJO_LOG_LEVEL_HEADER = "IPOJO-log-level";
     /**
-     * The Log Level ERROR.
+     * A shared log service implementation writing messages on the console.
      */
-    public static final int ERROR = Log.ERROR;
-
-    /**
-     * The Log Level WARNING.
-     */
-    public static final int WARNING = Log.WARNING;
-
-    /**
-     * The Log Level INFO.
-     */
-    public static final int INFO = Log.INFO;
-
-    /**
-     * The Log Level DEBUG.
-     */
-    public static final int DEBUG = Log.DEBUG;
-
+    private static final LogService m_defaultLogger = new ConsoleLogService();
+    private static final String DEBUG_HEADER = "[DEBUG]";
+    private static final String INFO_HEADER = "[INFO]";
+    private static final String WARNING_HEADER = "[WARNING]";
+    private static final String ERROR_HEADER = "[ERROR]";
+    private static final String UNKNOWN_HEADER = "[UNKNOWN]";
     /**
      * The Bundle Context used to get the
      * log service.
      */
-    private BundleContext m_context;
-
+    private final BundleContext m_context;
     /**
      * The name of the logger.
      */
-    private String m_name;
-
+    private final String m_name;
+    /**
+     * The trace level of this logger.
+     */
+    private final int m_level;
     /**
      * The instance associated to the logger if any.
      */
     private ComponentInstance m_instance;
 
     /**
-     * The trace level of this logger.
-     */
-    private int m_level;
-
-    /**
      * Creates a logger.
+     *
      * @param context the bundle context
-     * @param name the name of the logger
-     * @param level the trace level
+     * @param name    the name of the logger
+     * @param level   the trace level
      */
     public Logger(BundleContext context, String name, int level) {
         m_name = name;
@@ -102,22 +87,22 @@
 
     /**
      * Creates a logger.
-     * @param context the bundle context
+     *
+     * @param context  the bundle context
      * @param instance the instance
-     * @param level the trace level
+     * @param level    the trace level
      */
     public Logger(BundleContext context, ComponentInstance instance, int level) {
+        this(context, instance.getInstanceName(), level);
         m_instance = instance;
-        m_name = m_instance.getInstanceName();
-        m_level = level;
-        m_context = context;
     }
 
     /**
      * Create a logger.
      * Uses the default logger level.
+     *
      * @param context the bundle context
-     * @param name the name of the logger
+     * @param name    the name of the logger
      */
     public Logger(BundleContext context, String name) {
         this(context, name, getDefaultLevel(context));
@@ -126,7 +111,8 @@
     /**
      * Create a logger.
      * Uses the default logger level.
-     * @param context the bundle context
+     *
+     * @param context  the bundle context
      * @param instance the instance
      */
     public Logger(BundleContext context, ComponentInstance instance) {
@@ -134,216 +120,11 @@
     }
 
     /**
-     * Logs a message.
-     * @param level the level of the message
-     * @param msg the the message to log
-     */
-    public void log(int level, String msg) {
-        if (m_level >= level) {
-            dispatch(level, msg);
-        }
-        invokeErrorHandler(level, msg, null);
-    }
-
-    /**
-     * Logs a message with an exception.
-     * @param level the level of the message
-     * @param msg the message to log
-     * @param exception the exception attached to the message
-     */
-    public void log(int level, String msg, Throwable exception) {
-        if (m_level >= level) {
-            dispatch(level, msg, exception);
-        }
-        invokeErrorHandler(level, msg, exception);
-    }
-
-    /**
-     * Internal log method.
-     * @param level the level of the message.
-     * @param msg the message to log
-     */
-    private void dispatch(int level, String msg) {
-        LogService log = null;
-        ServiceReference ref = null;
-        try {
-            // Security Check
-            if (SecurityHelper.hasPermissionToGetService(LogService.class.getName(), m_context)) {
-                ref = m_context.getServiceReference(LogService.class.getName());
-            } else {
-                Extender.getIPOJOBundleContext().getServiceReference(LogService.class.getName());
-            }
-
-            if (ref != null) {
-                log = (LogService) m_context.getService(ref);
-            }
-        } catch (IllegalStateException e) {
-            // Handle the case where the iPOJO bundle is stopping
-        }
-
-        String message = null;
-        String name = m_name;
-        if (name == null) {
-            name = "";
-        }
-
-        switch (level) {
-            case DEBUG:
-                message = "[DEBUG] " + name + " : " + msg;
-                if (log != null) {
-                    log.log(LogService.LOG_DEBUG, message);
-                } else {
-                    System.err.println(message);
-                }
-                break;
-            case ERROR:
-                message = "[ERROR] " + name + " : " + msg;
-                if (log != null) {
-                    log.log(LogService.LOG_ERROR, message);
-                } else {
-                    System.err.println(message);
-                }
-                break;
-            case INFO:
-                message = "[INFO] " + name + " : " + msg;
-                if (log != null) {
-                    log.log(LogService.LOG_INFO, message);
-                } else {
-                    System.err.println(message);
-                }
-                break;
-            case WARNING:
-                message = "[WARNING] " + name + " : " + msg;
-                if (log != null) {
-                    log.log(LogService.LOG_WARNING, message);
-                } else {
-                    System.err.println(message);
-                }
-                break;
-            default:
-                message = "[UNKNOWN] " + name + " : " + msg;
-                System.err.println(message);
-                break;
-        }
-
-        if (log != null) {
-            m_context.ungetService(ref);
-        }
-    }
-
-    /**
-     * Internal log method.
-     * @param level the level of the message.
-     * @param msg the message to log
-     * @param exception the exception attached to the message
-     */
-    private void dispatch(int level, String msg, Throwable exception) {
-        LogService log = null;
-        ServiceReference ref = null;
-        try {
-            // Security Check
-            if (SecurityHelper.hasPermissionToGetService(LogService.class.getName(), m_context)) {
-                ref = m_context.getServiceReference(LogService.class.getName());
-            } else {
-                Extender.getIPOJOBundleContext().getServiceReference(LogService.class.getName());
-            }
-
-            if (ref != null) {
-                log = (LogService) m_context.getService(ref);
-            }
-        } catch (IllegalStateException e) {
-            // Handle the case where the iPOJO bundle is stopping
-        }
-
-        String message = null;
-        String name = m_name;
-        if (name == null) {
-            name = "";
-        }
-
-        switch (level) {
-            case DEBUG:
-                message = "[DEBUG] " + name + " : " + msg;
-                if (log != null) {
-                    log.log(LogService.LOG_DEBUG, message, exception);
-                } else {
-                    System.err.println(message);
-                    exception.printStackTrace();
-                }
-                break;
-            case ERROR:
-                message = "[ERROR] " + name + " : " + msg;
-                if (log != null) {
-                    log.log(LogService.LOG_ERROR, message, exception);
-                } else {
-                    System.err.println(message);
-                    exception.printStackTrace();
-                }
-                break;
-            case INFO:
-                message = "[INFO] " + name + " : " + msg;
-                if (log != null) {
-                    log.log(LogService.LOG_INFO, message, exception);
-                } else {
-                    System.err.println(message);
-                    exception.printStackTrace();
-                }
-                break;
-            case WARNING:
-                message = "[WARNING] " + name + " : " + msg;
-                if (log != null) {
-                    log.log(LogService.LOG_WARNING, message, exception);
-                } else {
-                    System.err.println(message);
-                    exception.printStackTrace();
-                }
-                break;
-            default:
-                message = "[UNKNOWN] " + name + " : " + msg;
-                System.err.println(message);
-                exception.printStackTrace();
-                break;
-        }
-
-        if (log != null) {
-            m_context.ungetService(ref);
-        }
-    }
-
-    /**
-     * Invokes the error handler service is present.
-     * @param level the log level
-     * @param msg the message
-     * @param error the error
-     */
-    private void invokeErrorHandler(int level, String msg, Throwable error) {
-        // First check the level
-        if (level > WARNING) {
-            return; // Others levels are not supported.
-        }
-        // Try to get the error handler service
-        try {
-            ServiceReference ref = m_context.getServiceReference(ErrorHandler.class.getName());
-            if (ref != null) {
-                ErrorHandler handler = (ErrorHandler) m_context.getService(ref);
-                if (level == ERROR) {
-                    handler.onError(m_instance, msg, error);
-                } else if (level == WARNING) {
-                    handler.onWarning(m_instance, msg, error);
-                } // The others case are not supported
-                m_context.ungetService(ref);
-            } // Else do nothing...
-        } catch (IllegalStateException e) {
-            // Ignore
-            // The iPOJO bundle is stopping.
-        }
-    }
-
-    /**
      * Gets the default logger level.
      * The property is searched inside the framework properties,
      * the system properties, and in the manifest from the given
      * bundle context. By default, set the level to {@link Logger#WARNING}.
+     *
      * @param context the bundle context.
      * @return the default log level.
      */
@@ -379,4 +160,159 @@
         return WARNING;
 
     }
+
+    private static String getLogHeaderForLevel(int level) {
+        switch (level) {
+            case DEBUG:
+                return DEBUG_HEADER;
+            case INFO:
+                return INFO_HEADER;
+            case WARNING:
+                return WARNING_HEADER;
+            case ERROR:
+                return ERROR_HEADER;
+            default:
+                return UNKNOWN_HEADER;
+        }
+    }
+
+    /**
+     * Logs a message.
+     *
+     * @param level the level of the message
+     * @param msg   the the message to log
+     */
+    public void log(int level, String msg) {
+        if (m_level >= level) {
+            dispatch(level, msg, null);
+        }
+        invokeErrorHandler(level, msg, null);
+    }
+
+    /**
+     * Logs a message with an exception.
+     *
+     * @param level     the level of the message
+     * @param msg       the message to log
+     * @param exception the exception attached to the message
+     */
+    public void log(int level, String msg, Throwable exception) {
+        if (m_level >= level) {
+            dispatch(level, msg, exception);
+        }
+        invokeErrorHandler(level, msg, exception);
+    }
+
+    /**
+     * Internal log method.
+     *
+     * @param level     the level of the message.
+     * @param msg       the message to log
+     * @param exception the exception attached to the message
+     */
+    private void dispatch(int level, String msg, Throwable exception) {
+        LogService log = null;
+        ServiceReference ref = null;
+        try {
+            // Security Check
+            if (SecurityHelper.hasPermissionToGetService(LogService.class.getName(), m_context)) {
+                ref = m_context.getServiceReference(LogService.class.getName());
+            } else {
+                Extender.getIPOJOBundleContext().getServiceReference(LogService.class.getName());
+            }
+
+            if (ref != null) {
+                log = (LogService) m_context.getService(ref);
+            }
+        } catch (IllegalStateException e) {
+            // Handle the case where the iPOJO bundle is stopping, or the log service already ran away.
+        }
+
+        if (log == null) {
+            log = m_defaultLogger;
+        }
+
+        String name = m_name;
+        if (name == null) {
+            name = "";
+        }
+
+        String message = String.format("%s %s : %s", getLogHeaderForLevel(level), name, msg);
+        switch (level) {
+            case DEBUG:
+                log.log(LogService.LOG_DEBUG, message, exception);
+                break;
+            case INFO:
+                log.log(LogService.LOG_INFO, message, exception);
+                break;
+            case WARNING:
+                log.log(LogService.LOG_WARNING, message, exception);
+                break;
+            case ERROR:
+                log.log(LogService.LOG_ERROR, message, exception);
+                break;
+            default:
+                log.log(LogService.LOG_INFO, message, exception);
+                break;
+        }
+
+        if (ref != null) {
+            m_context.ungetService(ref);
+        }
+    }
+
+    /**
+     * Invokes the error handler service is present.
+     *
+     * @param level the log level
+     * @param msg   the message
+     * @param error the error
+     */
+    private void invokeErrorHandler(int level, String msg, Throwable error) {
+        // First check the level
+        if (level > WARNING) {
+            return; // Others levels are not supported.
+        }
+        // Try to get the error handler service
+        try {
+            ServiceReference ref = m_context.getServiceReference(ErrorHandler.class.getName());
+            if (ref != null) {
+                ErrorHandler handler = (ErrorHandler) m_context.getService(ref);
+                if (level == ERROR) {
+                    handler.onError(m_instance, msg, error);
+                } else if (level == WARNING) {
+                    handler.onWarning(m_instance, msg, error);
+                } // The others case are not supported
+                m_context.ungetService(ref);
+            } // Else do nothing...
+        } catch (IllegalStateException e) {
+            // Ignore
+            // The iPOJO bundle is stopping.
+        }
+    }
+
+    /**
+     * A simple log service implementation writing the messages and stack trace on System.err.
+     */
+    private static class ConsoleLogService implements LogService {
+
+        public void log(int i, String s) {
+            log(i, s, null);
+        }
+
+        public void log(int level, String message, Throwable exception) {
+            System.err.println(message);
+            if (exception != null) {
+                exception.printStackTrace();
+            }
+        }
+
+        public void log(ServiceReference serviceReference, int i, String s) {
+            // not used.
+        }
+
+        public void log(ServiceReference serviceReference, int i, String s, Throwable throwable) {
+            // not used.
+        }
+    }
 }