Fix FELIX-2705 Provide a way to extend the logger strategy
Define a new ErrorHandler service interface. The iPOJO logger invokes this services when a warning or an error is thrown.

Also generalize the usage of the logger

Add tests about FELIX-2705 and re-enable logger tests.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1037859 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/ErrorHandler.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/ErrorHandler.java
new file mode 100644
index 0000000..4792594
--- /dev/null
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/ErrorHandler.java
@@ -0,0 +1,45 @@
+/*
+ * 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.felix.ipojo;
+
+/**
+ * Error Handler Service Definition.
+ * When exposed, this service is invoked when iPOJO throws a warning
+ * or an error. It's a hook on the internal iPOJO logger.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ErrorHandler {
+
+	/**
+	 * Method invokes when an error occurred.
+	 * @param instance the instance (can be <code>null</null>)
+	 * @param message the error message
+	 * @param error the error itself (can be <code>null</code>)
+	 */
+	public void onError(ComponentInstance instance, String message, Throwable error);
+
+	/**
+	 * Method invokes when a warning occurred.
+	 * @param instance the instance (can be <code>null</null>)
+	 * @param message the error message
+	 * @param error the error itself (can be <code>null</code>)
+	 */
+	public void onWarning(ComponentInstance instance, String message, Throwable error);
+
+}
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java
index 3ffa2b2..49f1649 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java
@@ -98,7 +98,7 @@
     protected List m_listeners = new ArrayList(1);

 

     /**

-     * The logger for the factory (and all component instances).

+     * The logger for the factory.

      */

     protected final Logger m_logger;

 

diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
index fa48335..25b0cce 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -341,6 +341,7 @@
             try {
                 m_factory = factory;
                 m_instance = m_factory.createComponentInstance(m_configuration);
+                m_logger.log(Logger.INFO, "Instance created");
             } catch (UnacceptableConfiguration e) {
                 m_logger.log(Logger.ERROR, "A matching factory was found for " + m_configuration + ", but the instantiation failed : "
                         + e.getMessage());
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
index e8d6210..709d70c 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
@@ -84,6 +84,11 @@
     private final ComponentFactory m_factory;
 
     /**
+     * The instance logger.
+     */
+    private final Logger m_logger;
+
+    /**
      * The instance description.
      */
     private final PrimitiveInstanceDescription m_description;
@@ -153,6 +158,15 @@
         m_context = context;
         m_handlers = handlers;
         m_description = new PrimitiveInstanceDescription(m_factory.getComponentDescription(), this);
+        m_logger = new Logger(m_context, this);
+    }
+
+    /**
+     * The instance logger.
+     * @return the logger
+     */
+    public Logger getLogger() {
+    	return m_logger;
     }
 
     /**
@@ -263,13 +277,13 @@
                 }
                 return field.get(pojo);
             } catch (SecurityException e) {
-                m_factory.getLogger().log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
+                m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
             } catch (NoSuchFieldException e) {
-                m_factory.getLogger().log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
+                m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
             } catch (IllegalArgumentException e) {
-                m_factory.getLogger().log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
+                m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
             } catch (IllegalAccessException e) {
-                m_factory.getLogger().log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
+                m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
             }
             return null;
         } else {
@@ -302,7 +316,7 @@
             try {
                 m_handlers[i].start();
             } catch (IllegalStateException e) {
-                m_factory.getLogger().log(Logger.ERROR, e.getMessage());
+                m_logger.log(Logger.ERROR, e.getMessage());
                 stop();
                 throw e;
             }
@@ -443,6 +457,7 @@
                 } catch (IllegalStateException e) {
                     // When an illegal state exception happens, the instance manager must be stopped immediately.
                     stop();
+                    m_logger.log(Logger.ERROR, e.getMessage(), e);
                     return;
                 }
             } else {
@@ -454,6 +469,7 @@
                 } catch (IllegalStateException e) {
                     // When an illegal state exception happens, the instance manager must be stopped immediately.
                     stop();
+                    m_logger.log(Logger.ERROR, e.getMessage());
                     return;
                 }
             }
@@ -541,7 +557,7 @@
         try {
             m_clazz = m_factory.loadClass(m_className);
         } catch (ClassNotFoundException e) {
-            m_factory.getLogger().log(Logger.ERROR, "[" + m_name + "] Class not found during the loading phase : " + e.getMessage());
+            m_logger.log(Logger.ERROR, "[" + m_name + "] Class not found during the loading phase : " + e.getMessage(), e);
             stop();
             return;
         }
@@ -603,40 +619,39 @@
                     }
                 }
             } catch (IllegalAccessException e) {
-                m_factory.getLogger().log(Logger.ERROR,
-                                          "[" + m_name + "] createInstance -> The POJO constructor is not accessible : " + e.getMessage());
+                m_logger.log(Logger.ERROR,
+                                          "[" + m_name + "] createInstance -> The POJO constructor is not accessible : " + e.getMessage(), e);
                 stop();
                 throw new RuntimeException("Cannot create a POJO instance, the POJO constructor is not accessible : " + e.getMessage());
             } catch (SecurityException e) {
-                m_factory.getLogger().log(
+                m_logger.log(
                                           Logger.ERROR,
                                           "["
                                                   + m_name
                                                   + "] createInstance -> The POJO constructor is not accessible (security reason) : "
-                                                  + e.getMessage());
+                                                  + e.getMessage(), e);
                 stop();
                 throw new RuntimeException("Cannot create a POJO instance, the POJO constructor is not accessible : " + e.getMessage());
             } catch (InvocationTargetException e) {
-                m_factory.getLogger().log(
+                m_logger.log(
                                           Logger.ERROR,
                                           "["
                                                   + m_name
                                                   + "] createInstance -> Cannot invoke the constructor method - the constructor throws an exception : "
-                                                  + e.getTargetException().getMessage());
+                                                  + e.getTargetException().getMessage(), e.getTargetException());
                 onError(null, m_className, e.getTargetException());
                 stop();
                 throw new RuntimeException("Cannot create a POJO instance, the POJO constructor has thrown an exception: " + e.getTargetException().getMessage());
             } catch (NoSuchMethodException e) {
-                m_factory.getLogger().log(Logger.ERROR,
-                                          "[" + m_name + "] createInstance -> Cannot invoke the constructor (method not found) : " + e.getMessage());
+                m_logger.log(Logger.ERROR,
+                                          "[" + m_name + "] createInstance -> Cannot invoke the constructor (method not found) : " + e.getMessage(), e);
                 stop();
                 throw new RuntimeException("Cannot create a POJO instance, the POJO constructor cannot be found : " + e.getMessage());
             } catch (Throwable e) {
                 // Catch every other possible error and runtime exception.
-                m_factory.getLogger().log(Logger.ERROR,
-                        "[" + m_name + "] createInstance -> The POJO constructor invocation failed : " + e.getMessage());
+                m_logger.log(Logger.ERROR,
+                        "[" + m_name + "] createInstance -> The POJO constructor invocation failed : " + e.getMessage(), e);
                 stop();
-                e.printStackTrace();
                 throw new RuntimeException("Cannot create a POJO instance, the POJO constructor invocation has thrown an exception : " + e.getMessage());
             }
         } else {
@@ -664,12 +679,12 @@
                         instance = factory.invoke(null, args);
                     } catch (NoSuchMethodException e2) {
                         // Error : factory-method not found
-                        m_factory.getLogger().log(
+                        m_logger.log(
                                                   Logger.ERROR,
                                                   "["
                                                           + m_name
                                                           + "] createInstance -> Cannot invoke the factory-method (method not found) : "
-                                                          + e2.getMessage());
+                                                          + e2.getMessage(), e2);
                         stop();
                         throw new RuntimeException("Cannot create a POJO instance, the factory-method cannot be found : " + e2.getMessage());
                     }
@@ -685,26 +700,26 @@
 
             } catch (InvocationTargetException e) {
                 // Error : invocation failed
-                m_factory.getLogger().log(Logger.ERROR,
-                                          "[" + m_name + "] createInstance -> The factory-method throws an exception : " + e.getTargetException());
+                m_logger.log(Logger.ERROR,
+                                          "[" + m_name + "] createInstance -> The factory-method throws an exception : " + e.getTargetException(), e.getTargetException());
                 onError(null, m_className, e.getTargetException());
                 stop();
                 throw new RuntimeException("Cannot create a POJO instance, the factory-method has thrown an exception: " + e.getTargetException().getMessage());
             } catch (NoSuchMethodException e) {
                 // Error : _setInstanceManager method is missing
-                m_factory.getLogger()
+                m_logger
                         .log(
                              Logger.ERROR,
                              "["
                                      + m_name
                                      + "] createInstance -> Cannot invoke the factory-method (the _setInstanceManager method does not exist) : "
-                                     + e.getMessage());
+                                     + e.getMessage(), e);
                 stop();
                 throw new RuntimeException("Cannot create a POJO instance, the factory-method cannot be found : " + e.getMessage());
             } catch (Throwable e) {
                 // Catch every other possible error and runtime exception.
-                m_factory.getLogger().log(Logger.ERROR,
-                        "[" + m_name + "] createInstance -> The factory-method invocation failed : " + e.getMessage());
+                m_logger.log(Logger.ERROR,
+                        "[" + m_name + "] createInstance -> The factory-method invocation failed : " + e.getMessage(), e);
                 stop();
                 throw new RuntimeException("Cannot create a POJO instance, the factory-method invocation has thrown an exception : " + e.getMessage());
             }
@@ -949,7 +964,7 @@
                 if (result != initialValue) {
                     //TODO analyze impact of removing conflict detection
                     if ((handlerResult != null && !handlerResult.equals(result)) || (result != null && handlerResult == null)) {
-                        m_factory.getLogger().log(
+                        m_logger.log(
                                                   Logger.WARNING,
                                                   "A conflict was detected on the injection of "
                                                           + fieldName);
@@ -1069,7 +1084,7 @@
                 return null;
             }
             // Cannot happen
-            m_factory.getLogger().log(Logger.ERROR, "A methodID cannot be associated with a method from the POJO class: " + methodId);
+            m_logger.log(Logger.ERROR, "A methodID cannot be associated with a method from the POJO class: " + methodId);
             return null;
         } else {
             return method;
@@ -1158,17 +1173,17 @@
      * @see org.apache.felix.ipojo.ComponentInstance#reconfigure(java.util.Dictionary)
      */
     public void reconfigure(Dictionary configuration) {
-    	 m_factory.getLogger().log(Logger.INFO, "Reconfiguring " + getInstanceName());
+    	 m_logger.log(Logger.INFO, "Reconfiguring " + getInstanceName());
         for (int i = 0; i < m_handlers.length; i++) {
             m_handlers[i].getHandler().reconfigure(configuration);
         }
         // We synchronized the state computation.
         synchronized (this) {
         	if (m_state == STOPPED) {
-        		m_factory.getLogger().log(Logger.INFO, "Instance stopped during reconfiguration - Try to restart");
+        		m_logger.log(Logger.INFO, "Instance stopped during reconfiguration - Try to restart");
         		start();
         	} else if (m_state == INVALID) {
-        		m_factory.getLogger().log(Logger.INFO, "Instance invalid during reconfiguration - Recompute state");
+        		m_logger.log(Logger.INFO, "Instance invalid during reconfiguration - Recompute state");
                 // Try to revalidate the instance after reconfiguration
                 for (int i = 0; i < m_handlers.length; i++) {
                     if (m_handlers[i].getState() != VALID) {
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java
index 7e15c11..94a7544 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java
@@ -1,4 +1,4 @@
-/* 

+/*

  * 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

@@ -34,23 +34,28 @@
 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

 */

 public abstract class PrimitiveHandler extends Handler implements FieldInterceptor, MethodInterceptor {

-    

+

     /**

      * The "Primitive" Handler type (value).

      */

     public static final String HANDLER_TYPE = "primitive";

-    

+

     /**

      * The reference on the instance manager.

      */

     private InstanceManager m_manager;

-    

-    

+

+

     /**

-     * The factory of the instance manager. 

+     * The factory of the instance manager.

      */

     private ComponentFactory m_factory;

-    

+

+	/**

+	 * Instance Logger used by the handler.

+	 */

+	private Logger m_instanceLogger;

+

     /**

      * Attaches the current handler to the given instance.

      * @param manager the instance on which the current handler will be attached.

@@ -58,26 +63,31 @@
      */

     protected final void attach(ComponentInstance manager) {

         m_manager = (InstanceManager) manager;

+        m_instanceLogger = m_manager.getLogger();

     }

-    

+

     /**

      * Sets the factory of the managed instance.

-     * @param factory the factory 

+     * @param factory the factory

      * @see org.apache.felix.ipojo.Handler#setFactory(org.apache.felix.ipojo.Factory)

      */

     public final void setFactory(Factory factory) {

         m_factory = (ComponentFactory) factory;

     }

-    

+

     /**

-     * gets the logger of the managed instance.

+     * Gets the logger of the managed instance.

+     * IF no instance attached yet, use the factory logger.

      * @return the logger to use to log messages.

      * @see org.apache.felix.ipojo.Handler#getLogger()

      */

     public Logger getLogger() {

-        return m_factory.getLogger();

+    	if (m_instanceLogger == null) {

+    		return m_factory.getLogger();

+    	}

+        return m_instanceLogger;

     }

-    

+

     /**

      * Gets the instance manager managing the instance.

      * @return the instance manager

@@ -85,7 +95,7 @@
     public InstanceManager getInstanceManager() {

         return m_manager;

     }

-    

+

     /**

      * Gets the factory which creates the managed instance.

      * @return the factory which creates the managed instance.

@@ -93,7 +103,7 @@
     public ComponentFactory getFactory() {

         return m_factory;

     }

-    

+

     /**

      * Gets the PojoMetadata of the content of the managed

      * instance. This method allows getting manipulation

@@ -104,25 +114,25 @@
     public PojoMetadata getPojoMetadata() {

         return m_factory.getPojoMetadata();

     }

-    

+

     /**

      * Gets a plugged handler of the same container.

-     * This method must be called only in the start method (or after). 

+     * This method must be called only in the start method (or after).

      * In the configure method, this method can be inconsistent

-     * as all handlers are not initialized. 

+     * as all handlers are not initialized.

      * @param name the name of the handler to find (class name or qualified

-     * handler name (<code>ns:name</code>)). 

+     * handler name (<code>ns:name</code>)).

      * @return the handler object or <code>null</code> if the handler is not found.

      */

     public final Handler getHandler(String name) {

         return m_manager.getHandler(name);

     }

-    

+

     /**

-     * Callback method called when a managed field 

+     * Callback method called when a managed field

      * receives a new value. The given pojo can be

      * null if the new value is set by another handler.

-     * This default implementation does nothing. 

+     * This default implementation does nothing.

      * @param pojo the pojo object setting the value

      * @param fieldName the field name

      * @param value the value received by the field

@@ -147,23 +157,23 @@
     public Object onGet(Object pojo, String fieldName, Object value) {

         return value;

     }

-    

+

     /**

      * Callback method called when a method will be invoked.

-     * This default implementation does nothing. 

+     * This default implementation does nothing.

      * @param pojo the pojo on which the method is called.

      * @param method the method invoked.

      * @param args the arguments array.

      * @see MethodInterceptor#onEntry(Object, Method, Object[])

      */

-    public void onEntry(Object pojo, Method method, Object[] args) { 

+    public void onEntry(Object pojo, Method method, Object[] args) {

         // Nothing to do in the default implementation

     }

 

     /**

      * Callback method called when a method ends.

      * This method is called when a thread exits a method (before a return or a throw).

-     * If the given returned object is <code>null</code>, either the method is 

+     * If the given returned object is <code>null</code>, either the method is

      * <code>void</code>, or it returns <code>null</code>.

      * You must not modified the returned object.

      * The default implementation does nothing.

@@ -172,13 +182,13 @@
      * @param returnedObj the returned object (boxed for primitive type)

      * @see MethodInterceptor#onExit(Object, Method, Object)

      */

-    public void onExit(Object pojo, Method method, Object returnedObj) { 

+    public void onExit(Object pojo, Method method, Object returnedObj) {

         // Nothing to do in the default implementation

     }

-    

+

     /**

      * Callback method called when an error occurs.

-     * This method is called when the execution throws an exception 

+     * This method is called when the execution throws an exception

      * in the given method.

      * The default implementation does nothing.

      * @param pojo the pojo on which the method was accessed.

@@ -189,12 +199,12 @@
     public void onError(Object pojo, Method method, Throwable throwable) {

         // Nothing to do in the default implementation

     }

-    

+

     /**

-     * Callback method called when the execution of a method will terminate : 

+     * Callback method called when the execution of a method will terminate :

      * just before to throw an exception or before to return.

      * {@link MethodInterceptor#onExit(Object, Method, Object)} or

-     * {@link MethodInterceptor#onError(Object, Method, Throwable)} 

+     * {@link MethodInterceptor#onError(Object, Method, Throwable)}

      * were already called.

      * This default implementation does nothing.

      * @param pojo the pojo on which the method was accessed.

@@ -203,17 +213,17 @@
     public void onFinally(Object pojo, Method method) {

         // Nothing to do in the default implementation

     }

-    

+

     /**

      * Callback method called when an instance of the component is created, but

      * before someone can use it.

      * The default implementation does nothing.

      * @param instance the created instance

      */

-    public void onCreation(Object instance) { 

+    public void onCreation(Object instance) {

         // Nothing to do in the default implementation

     }

-    

-    

+

+

 

 }

diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
index bdbb269..c41c6f8 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
@@ -297,10 +297,10 @@
                 callback.callOnInstance(pojo, ref, getService(ref));
             }
         } catch (NoSuchMethodException e) {
-            m_handler.error("The method " + callback.getMethodName() + " does not exist in the implementation class " + m_handler.getInstanceManager().getClassName());
+            m_handler.error("The method " + callback.getMethodName() + " does not exist in the implementation class " + m_handler.getInstanceManager().getClassName(), e);
             m_handler.getInstanceManager().stop();
         } catch (IllegalAccessException e) {
-            m_handler.error("The method " + callback.getMethodName() + " is not accessible in the implementation class " + m_handler.getInstanceManager().getClassName());
+            m_handler.error("The method " + callback.getMethodName() + " is not accessible in the implementation class " + m_handler.getInstanceManager().getClassName(), e);
             m_handler.getInstanceManager().stop();
         } catch (InvocationTargetException e) {
             m_handler.error("The method " + callback.getMethodName() + " in the implementation class " + m_handler.getInstanceManager().getClassName() + " throws an exception : " + e.getTargetException().getMessage(), e.getTargetException());
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
index 1f6169d..f9f0643 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
@@ -179,7 +179,7 @@
                         + m_handler.getInstanceManager().getInstanceName()
                         + "] The customized service object creation policy "
                         + "(" + creationStrategyClass.getName() + ") is not accessible: "
-                        + e.getMessage());
+                        + e.getMessage(), e);
                 getInstanceManager().stop();
                 return;
             } catch (InstantiationException e) {
@@ -187,7 +187,7 @@
                         + m_handler.getInstanceManager().getInstanceName()
                         + "] The customized service object creation policy "
                         + "(" + creationStrategyClass.getName() + ") cannot be instantiated: "
-                        + e.getMessage());
+                        + e.getMessage(), e);
                 getInstanceManager().stop();
                 return;
             }
@@ -332,7 +332,7 @@
         if (m_serviceRegistration != null) {
             unregisterService();
         }
-        
+
         if (m_handler.getInstanceManager().getState() == ComponentInstance.VALID
                 && m_serviceRegistration == null  && isAtLeastAServiceControllerValid()) {
             // Build the service properties list
@@ -372,7 +372,7 @@
     protected synchronized void unregisterService() {
     	// Create a copy of the service reference in the case we need
     	// to inject it to the post-unregistration callback.
-        
+
     	ServiceReference ref = null;
         if (m_serviceRegistration != null) {
     		ref = m_serviceRegistration.getReference();
@@ -526,11 +526,11 @@
         }
         return null;
     }
-    
+
     public ServiceController getControllerBySpecification(String spec) {
         return (ServiceController) m_controllers.get(spec);
     }
-    
+
     /**
      * Checks if at least one service controller is valid.
      * @return <code>true</code> if one service controller at least
@@ -538,12 +538,12 @@
      */
     private boolean isAtLeastAServiceControllerValid() {
         Collection controllers = m_controllers.values();
-        
+
         // No controller
         if (controllers.isEmpty()) {
             return true;
         }
-        
+
         Iterator iterator = controllers.iterator();
         while (iterator.hasNext()) {
             ServiceController controller = (ServiceController) iterator.next();
@@ -553,12 +553,12 @@
         }
         return false;
     }
-    
+
     private String[] getServiceSpecificationsToRegister() {
         if (m_controllers.isEmpty()) {
             return m_serviceSpecifications;
         }
-        
+
         ArrayList l = new ArrayList();
         if (m_controllers.containsKey("ALL")) {
             ServiceController ctrl = (ServiceController) m_controllers.get("ALL");
@@ -566,7 +566,7 @@
                 l.addAll(Arrays.asList(m_serviceSpecifications));
             }
         }
-        
+
         Iterator iterator = m_controllers.keySet().iterator();
         while (iterator.hasNext()) {
             String spec = (String) iterator.next();
@@ -581,9 +581,9 @@
                 l.remove(spec);
             }
         }
-                
+
         return (String[]) l.toArray(new String[l.size()]);
-        
+
     }
 
     public void setPostRegistrationCallback(Callback cb) {
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Logger.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
index 3c8029c..5382603 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.ipojo.util;
 
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ErrorHandler;
 import org.apache.felix.ipojo.Extender;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -25,23 +27,25 @@
 
 /**
  * iPOJO Logger.
- * This class is an helper class implementing a simple log system. 
+ * This class is an helper class implementing a simple log system.
  * This logger sends log messages to a log service if available.
- * 
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class Logger {
-    
+
     /**
      * 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.
@@ -75,6 +79,11 @@
     private String m_name;
 
     /**
+     * The instance associated to the logger if any.
+     */
+    private ComponentInstance m_instance;
+
+    /**
      * The trace level of this logger.
      */
     private int m_level;
@@ -90,7 +99,20 @@
         m_level = level;
         m_context = context;
     }
-    
+
+    /**
+     * Creates a logger.
+     * @param context the bundle context
+     * @param instance the instance
+     * @param level the trace level
+     */
+    public Logger(BundleContext context, ComponentInstance instance, int level) {
+        m_instance = instance;
+    	m_name = m_instance.getInstanceName();
+        m_level = level;
+        m_context = context;
+    }
+
     /**
      * Create a logger.
      * Uses the default logger level.
@@ -102,6 +124,16 @@
     }
 
     /**
+     * Create a logger.
+     * Uses the default logger level.
+     * @param context the bundle context
+     * @param instance the instance
+     */
+    public Logger(BundleContext context, ComponentInstance instance) {
+        this(context, instance, getDefaultLevel(context));
+    }
+
+    /**
      * Logs a message.
      * @param level the level of the message
      * @param msg the the message to log
@@ -110,6 +142,7 @@
         if (m_level >= level) {
             dispatch(level, msg);
         }
+        invokeErrorHandler(level, msg, null);
     }
 
     /**
@@ -122,10 +155,11 @@
         if (m_level >= level) {
             dispatch(level, msg, exception);
         }
+        invokeErrorHandler(level, msg, exception);
     }
-    
+
     /**
-     * Internal log method. 
+     * Internal log method.
      * @param level the level of the message.
      * @param msg the message to log
      */
@@ -139,7 +173,7 @@
             } else {
                 Extender.getIPOJOBundleContext().getServiceReference(LogService.class.getName());
             }
-            
+
             if (ref != null) {
                 log = (LogService) m_context.getService(ref);
             }
@@ -186,7 +220,7 @@
                 System.err.println(message);
                 break;
         }
-        
+
         if (log != null) {
             m_context.ungetService(ref);
         }
@@ -208,14 +242,14 @@
             } 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;
         switch (level) {
             case DEBUG:
@@ -260,35 +294,65 @@
                 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);
+	    		return;
+	    	} // 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}. 
+     * 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.
      */
     private static int getDefaultLevel(BundleContext context) {
         // First check in the framework and in the system properties
         String level = context.getProperty(IPOJO_LOG_LEVEL_PROP);
-        
+
         // If null, look in the bundle manifest
         if (level == null) {
             String key = IPOJO_LOG_LEVEL_PROP.replace('.', '-');
             level = (String) context.getBundle().getHeaders().get(key);
         }
-        
+
         // if still null try the second header
         if (level == null) {
             level = (String) context.getBundle().getHeaders().get(IPOJO_LOG_LEVEL_HEADER);
         }
-                
+
         if (level != null) {
             if (level.equalsIgnoreCase("info")) {
                 return INFO;
@@ -300,10 +364,10 @@
                 return ERROR;
             }
         }
-        
+
         // Either l is null, either the specified log level was unknown
         // Set the default to WARNING
         return WARNING;
-        
+
     }
 }
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java
index f7bc98c..a2d3534 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java
@@ -527,10 +527,10 @@
             }

             m_invoked = true;

         } catch (NoSuchMethodException e) {

-            m_handler.error("The method " + m_method + " does not exist in the implementation class " + m_manager.getClassName());

+            m_handler.error("The method " + m_method + " does not exist in the implementation class " + m_manager.getClassName(), e);

             m_manager.stop();

         } catch (IllegalAccessException e) {

-            m_handler.error("The method " + m_method + " is not accessible in the implementation class " + m_manager.getClassName());

+            m_handler.error("The method " + m_method + " is not accessible in the implementation class " + m_manager.getClassName(), e);

             m_manager.stop();

         } catch (InvocationTargetException e) {

             m_handler.error("The method " + m_method + " in the implementation class " + m_manager.getClassName() + "throws an exception : " + e.getTargetException().getMessage(), e.getTargetException());

diff --git a/ipojo/tests/core/logger/erroneous-component.xml b/ipojo/tests/core/logger/erroneous-component.xml
new file mode 100644
index 0000000..9ac7735
--- /dev/null
+++ b/ipojo/tests/core/logger/erroneous-component.xml
@@ -0,0 +1,5 @@
+<ipojo>
+<component immediate="true" classname="org.apache.felix.ipojo.tests.core.component.MyErroneousComponent">
+  <provides/>
+</component>
+</ipojo>
diff --git a/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/ErrorHandlerTest.java b/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/ErrorHandlerTest.java
new file mode 100644
index 0000000..1e0f7d6
--- /dev/null
+++ b/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/ErrorHandlerTest.java
@@ -0,0 +1,160 @@
+package org.apache.felix.ipojo.tests.core;
+
+import static org.ops4j.pax.exam.CoreOptions.felix;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.newBundle;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOBuilder.withiPOJO;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ErrorHandler;
+import org.apache.felix.ipojo.tests.core.component.MyComponent;
+import org.apache.felix.ipojo.tests.core.component.MyErroneousComponent;
+import org.apache.felix.ipojo.tests.core.service.MyService;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Inject;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+
+@RunWith( JUnit4TestRunner.class )
+public class ErrorHandlerTest {
+
+    @Inject
+    private BundleContext context;
+
+    private OSGiHelper osgi;
+
+    private IPOJOHelper ipojo;
+
+    @Before
+    public void init() {
+        osgi = new OSGiHelper(context);
+        ipojo = new IPOJOHelper(context);
+    }
+
+    @After
+    public void stop() {
+        ipojo.dispose();
+        osgi.dispose();
+    }
+
+    @Configuration
+    public static Option[] configure() {
+
+        File tmp = new File("target/tmp");
+        tmp.mkdirs();
+
+        Option[] opt =  options(
+                felix(),
+//                equinox(),
+                provision(
+                        // Runtime.
+                        mavenBundle().groupId( "org.apache.felix" ).artifactId( "org.apache.felix.log" ).version(asInProject()),
+                        mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo").version(asInProject()),
+                        mavenBundle().groupId("org.ow2.chameleon.testing").artifactId("osgi-helpers").versionAsInProject()
+                        ),
+                provision(
+                        newBundle()
+                            .add( MyService.class )
+                            .set(Constants.BUNDLE_SYMBOLICNAME,"ServiceInterface")
+                            .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
+                            .build()
+                    ),
+               provision(
+                       // Component
+                        newBundle()
+                            .add(MyComponent.class)
+                            .set(Constants.BUNDLE_SYMBOLICNAME,"MyComponent")
+                            .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
+                            .set("Ipojo-log-level", "info")
+                            .build( withiPOJO(new File(tmp, "provider-with-level-in-manifest.jar"), new File("component.xml")))
+                            ),
+                provision(
+                        // Component
+                         newBundle()
+                             .add(MyErroneousComponent.class)
+                             .set(Constants.BUNDLE_SYMBOLICNAME,"MyErroneousComponent")
+                             .set("Ipojo-log-level", "debug")
+                             .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
+                             .build( withiPOJO(new File(tmp, "erroneous-provider-with-level-in-manifest.jar"), new File("erroneous-component.xml")))
+                             )
+                );
+        return opt;
+    }
+
+    @Test
+    public void testErrorHandlerEmpty() throws InterruptedException, InvalidSyntaxException {
+    	MyErrorHandler handler = new MyErrorHandler();
+    	context.registerService(ErrorHandler.class.getName(), handler, null);
+
+        System.out.println(handler.m_errors);
+
+        Assert.assertTrue(handler.m_errors.isEmpty());
+    }
+
+    @Test
+    public void testErrorHandler() throws InterruptedException, InvalidSyntaxException {
+    	MyErrorHandler handler = new MyErrorHandler();
+    	context.registerService(ErrorHandler.class.getName(), handler, null);
+
+    	try {
+    		ipojo.createComponentInstance("org.apache.felix.ipojo.tests.core.component.MyErroneousComponent");
+    	} catch (Exception e ) {
+    		System.out.println(e);
+    	}
+
+
+        System.out.println(handler.m_errors);
+
+        Assert.assertFalse(handler.m_errors.isEmpty());
+        Assert.assertTrue(handler.m_errors.contains("org.apache.felix.ipojo.tests.core.component.MyErroneousComponent-0:[org.apache.felix.ipojo.tests.core.component.MyErroneousComponent-0] createInstance -> Cannot invoke the constructor method - the constructor throws an exception : bad:bad"));
+    }
+
+
+   private class MyErrorHandler implements ErrorHandler {
+
+	   private List<String> m_errors = new ArrayList<String>();
+
+	   public void onError(ComponentInstance instance, String message,
+				Throwable error) {
+		   System.out.println("on Error ! " + instance + " - " + message);
+			if (instance == null) {
+				if (error == null) {
+					m_errors.add("no-instance:" + message);
+				} else {
+					m_errors.add("no-instance:" + message + ":" + error.getMessage());
+				}
+			} else {
+				if (error == null) {
+					m_errors.add(instance.getInstanceName() + ":" + message);
+				} else {
+					m_errors.add(instance.getInstanceName() + ":" + message + ":" + error.getMessage());
+				}
+			}
+		}
+
+	   public void onWarning(ComponentInstance instance, String message,
+				Throwable error) {
+		   System.out.println("on warning ! " + instance + " - " + message);
+		}
+
+   }
+
+
+}
diff --git a/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/ManifestLoggerInfoTest.java b/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/ManifestLoggerInfoTest.java
index 7a9e9b7..5ca7c9d 100644
--- a/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/ManifestLoggerInfoTest.java
+++ b/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/ManifestLoggerInfoTest.java
@@ -1,5 +1,6 @@
 package org.apache.felix.ipojo.tests.core;
 
+import static org.ops4j.pax.exam.CoreOptions.equinox;
 import static org.ops4j.pax.exam.CoreOptions.felix;
 import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
 import static org.ops4j.pax.exam.CoreOptions.options;
@@ -9,6 +10,7 @@
 import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOBuilder.withiPOJO;
 
 import java.io.File;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Enumeration;
@@ -20,13 +22,14 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Customizer;
 import org.ops4j.pax.exam.Inject;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.Configuration;
 import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.ops4j.pax.swissbox.tinybundles.core.TinyBundles;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -78,7 +81,7 @@
 
         Option[] opt =  options(
                 felix(),
-//                equinox(),
+                equinox(),
                 provision(
                         // Runtime.
                         mavenBundle().groupId( "org.apache.felix" ).artifactId( "org.apache.felix.log" ).version(asInProject()),
@@ -98,15 +101,22 @@
                             .add(MyComponent.class)
                             .set(Constants.BUNDLE_SYMBOLICNAME,"MyComponent")
                             .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
-                            .set("ipojo-log-level", "info")
+                            .set("Ipojo-log-level", "info")
                             .build( withiPOJO(new File(tmp, "provider-with-level-in-manifest.jar"), new File("component.xml")))
-                            )
-                );
+                            ),
+                new Customizer() {
+                    @Override
+                    public InputStream customizeTestProbe( InputStream testProbe )
+                    {
+                       return TinyBundles.modifyBundle(testProbe)
+                           .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
+                           .build();
+                    }
+                });
         return opt;
     }
 
     @Test
-    @Ignore //TODO Why we have a classloading issue here ?
     public void testMessages() throws InterruptedException, InvalidSyntaxException {
         Bundle bundle = osgi.getBundle("MyComponent");
         Assert.assertNotNull(bundle);
@@ -123,9 +133,9 @@
 
 
 
-   //     Assert.assertNotNull(osgi.getServiceObject(MyService.class.getName(), null));
+        Assert.assertNotNull(osgi.getServiceObject(MyService.class.getName(), null));
 
-//        osgi.waitForService("org.apache.felix.ipojo.tests.core.service.MyService", null, 5000);
+        osgi.waitForService("org.apache.felix.ipojo.tests.core.service.MyService", null, 5000);
         List<String> messages = getMessages(log.getLog());
         System.out.println(messages);
         Assert.assertTrue(messages.contains("Ready"));
diff --git a/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/component/MyErroneousComponent.java b/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/component/MyErroneousComponent.java
new file mode 100644
index 0000000..feca648
--- /dev/null
+++ b/ipojo/tests/core/logger/src/test/java/org/apache/felix/ipojo/tests/core/component/MyErroneousComponent.java
@@ -0,0 +1,15 @@
+package org.apache.felix.ipojo.tests.core.component;
+
+import org.apache.felix.ipojo.tests.core.service.MyService;
+
+public class MyErroneousComponent implements MyService {
+
+	public MyErroneousComponent() {
+		throw new NullPointerException("bad");
+	}
+
+    public void foo() {
+        // Nothing to do.
+    }
+
+}