FELIX-639 add some logging for unexpected elements in the XML file and
add some very simple Logger interface helping with the logging in the
component metadata parsing and setup.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@741708 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
index fa24dfd..ee62499 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
@@ -42,7 +42,7 @@
  * a single bundle. It will read information from the metadata.xml file
  * descriptors and create the corresponding managers.
  */
-class BundleComponentActivator
+class BundleComponentActivator implements Logger
 {
     // global component registration
     private ComponentRegistry m_componentRegistry;
@@ -146,7 +146,7 @@
                 stream = descriptorURL.openStream();
 
                 BufferedReader in = new BufferedReader( new InputStreamReader( stream ) );
-                XmlHandler handler = new XmlHandler( m_context.getBundle() );
+                XmlHandler handler = new XmlHandler( m_context.getBundle(), this );
                 KXml2SAXParser parser;
 
                 parser = new KXml2SAXParser( in );
@@ -489,7 +489,7 @@
      * @param ex An optional <code>Throwable</code> whose stack trace is written,
      *      or <code>null</code> to not log a stack trace.
      */
-    void log( int level, String message, ComponentMetadata metadata, Throwable ex )
+    public void log( int level, String message, ComponentMetadata metadata, Throwable ex )
     {
 
         if ( m_logLevel >= level )
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java
index ecc798e..ee27ab5 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java
@@ -69,7 +69,6 @@
     // Flag that is set once the component is verified (its properties cannot be changed)
     private boolean m_validated = false;
 
-
     /////////////////////////////////////////// SETTERS //////////////////////////////////////
 
     /**
@@ -317,16 +316,7 @@
     /**
      * Method used to verify if the semantics of this metadata are correct
      */
-    void validate()
-    {
-        validate( null );
-    }
-
-
-    /**
-     * Method used to verify if the semantics of this metadata are correct
-     */
-    void validate( BundleComponentActivator bundleComponentActivator )
+    void validate( Logger logger )
     {
         // nothing to do if already validated
         if ( m_validated )
@@ -373,11 +363,8 @@
             // flag duplicates
             if ( !refs.add( refMeta.getName() ) )
             {
-                if ( bundleComponentActivator != null )
-                {
-                    bundleComponentActivator.log( LogService.LOG_WARNING, "Detected duplicate reference name: \""
-                        + refMeta.getName() + "\"", this, null );
-                }
+                logger.log( LogService.LOG_WARNING, "Detected duplicate reference name: \"" + refMeta.getName() + "\"",
+                    this, null );
             }
         }
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/XmlHandler.java b/scr/src/main/java/org/apache/felix/scr/impl/XmlHandler.java
index 1f05b43..b144734 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/XmlHandler.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/XmlHandler.java
@@ -27,6 +27,7 @@
 import org.apache.felix.scr.impl.parser.KXml2SAXHandler;
 import org.apache.felix.scr.impl.parser.ParseException;
 import org.osgi.framework.Bundle;
+import org.osgi.service.log.LogService;
 
 
 /**
@@ -39,7 +40,10 @@
     public static final String NAMESPACE_URI = "http://www.osgi.org/xmlns/scr/v1.0.0";
 
     // the bundle containing the XML resource being parsed
-    private Bundle m_bundle;
+    private final Bundle m_bundle;
+
+    // logger for any messages
+    private final Logger m_logger;
 
     // A reference to the current component
     private ComponentMetadata m_currentComponent;
@@ -65,9 +69,10 @@
 
     // creates an instance with the bundle owning the component descriptor
     // file parsed by this instance
-    XmlHandler( Bundle bundle )
+    XmlHandler( Bundle bundle, Logger logger )
     {
         m_bundle = bundle;
+        m_logger = logger;
     }
 
 
@@ -226,6 +231,13 @@
 
                     m_currentComponent.addDependency( ref );
                 }
+                
+                // unexpected element
+                else
+                {
+                    m_logger.log( LogService.LOG_INFO, "Ignoring unsupported element " + localName + " (bundle "
+                        + m_bundle.getLocation() + ")", null, null );
+                }
             }
             catch ( Exception ex )
             {
@@ -233,6 +245,13 @@
                 throw new ParseException( "Exception during parsing", ex );
             }
         }
+        
+        // unexpected namespace
+        else
+        {
+            m_logger.log( LogService.LOG_INFO, "Ignoring unsupported element {" + uri + "}" + localName + " (bundle "
+                + m_bundle.getLocation() + ")", null, null );
+        }
     }
 
 
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java b/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java
index 10dd3a2..2e79705 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java
@@ -27,6 +27,9 @@
 public class ComponentMetadataTest extends TestCase
 {
 
+    private TestLogger logger = new TestLogger();
+
+
     // test various combinations of component metadata with respect to
     //  -- immediate: true, false, unset
     //  -- factory: set, unset
@@ -37,24 +40,24 @@
     {
         // immediate is default true if no service element is defined
         final ComponentMetadata cm0 = createComponentMetadata( null, null );
-        cm0.validate();
+        cm0.validate( logger );
         assertTrue( "Component without service must be immediate", cm0.isImmediate() );
 
         // immediate is explicit true
         final ComponentMetadata cm1 = createComponentMetadata( Boolean.TRUE, null );
-        cm1.validate();
+        cm1.validate( logger );
         assertTrue( "Component must be immediate", cm1.isImmediate() );
 
         // immediate is explicit true
         final ComponentMetadata cm2 = createComponentMetadata( Boolean.TRUE, null );
         cm2.setService( createServiceMetadata( null ) );
-        cm2.validate();
+        cm2.validate( logger );
         assertTrue( "Component must be immediate", cm2.isImmediate() );
 
         // immediate is explicit true
         final ComponentMetadata cm3 = createComponentMetadata( Boolean.TRUE, null );
         cm3.setService( createServiceMetadata( Boolean.FALSE ) );
-        cm3.validate();
+        cm3.validate( logger );
         assertTrue( "Component must be immediate", cm3.isImmediate() );
 
         // validation failure of immediate with service factory
@@ -62,7 +65,7 @@
         cm4.setService( createServiceMetadata( Boolean.TRUE ) );
         try
         {
-            cm4.validate();
+            cm4.validate( logger );
             fail( "Expect validation failure for immediate service factory" );
         }
         catch ( ComponentException ce )
@@ -77,44 +80,44 @@
         // immediate is default false if service element is defined
         final ComponentMetadata cm0 = createComponentMetadata( null, null );
         cm0.setService( createServiceMetadata( null ) );
-        cm0.validate();
+        cm0.validate( logger );
         assertFalse( "Component with service must be delayed", cm0.isImmediate() );
 
         // immediate is default false if service element is defined
         final ComponentMetadata cm1 = createComponentMetadata( null, null );
         cm1.setService( createServiceMetadata( Boolean.TRUE ) );
-        cm1.validate();
+        cm1.validate( logger );
         assertFalse( "Component with service must be delayed", cm1.isImmediate() );
 
         // immediate is default false if service element is defined
         final ComponentMetadata cm2 = createComponentMetadata( null, null );
         cm2.setService( createServiceMetadata( Boolean.FALSE ) );
-        cm2.validate();
+        cm2.validate( logger );
         assertFalse( "Component with service must be delayed", cm2.isImmediate() );
 
         // immediate is false if service element is defined
         final ComponentMetadata cm3 = createComponentMetadata( Boolean.FALSE, null );
         cm3.setService( createServiceMetadata( null ) );
-        cm3.validate();
+        cm3.validate( logger );
         assertFalse( "Component with service must be delayed", cm3.isImmediate() );
 
         // immediate is false if service element is defined
         final ComponentMetadata cm4 = createComponentMetadata( Boolean.FALSE, null );
         cm4.setService( createServiceMetadata( Boolean.TRUE ) );
-        cm4.validate();
+        cm4.validate( logger );
         assertFalse( "Component with service must be delayed", cm4.isImmediate() );
 
         // immediate is false if service element is defined
         final ComponentMetadata cm5 = createComponentMetadata( Boolean.FALSE, null );
         cm5.setService( createServiceMetadata( Boolean.FALSE ) );
-        cm5.validate();
+        cm5.validate( logger );
         assertFalse( "Component with service must be delayed", cm5.isImmediate() );
 
         // explicit delayed fails when there is no service
         final ComponentMetadata cm6 = createComponentMetadata( Boolean.FALSE, null );
         try
         {
-            cm6.validate();
+            cm6.validate( logger );
             fail( "Expect validation failure for delayed component without service" );
         }
         catch ( ComponentException ce )
@@ -128,19 +131,19 @@
     {
         // immediate is default false if factory is defined
         final ComponentMetadata cm0 = createComponentMetadata( null, "factory" );
-        cm0.validate();
+        cm0.validate( logger );
         assertFalse( "Component with factory must be delayed", cm0.isImmediate() );
 
         // immediate is false if factory is defined
         final ComponentMetadata cm1 = createComponentMetadata( Boolean.FALSE, "factory" );
-        cm1.validate();
+        cm1.validate( logger );
         assertFalse( "Component with factory must be delayed", cm1.isImmediate() );
 
         // immediate is default false if factory is defined
         final ComponentMetadata cm2 = createComponentMetadata( Boolean.TRUE, "factory" );
         try
         {
-            cm2.validate();
+            cm2.validate( logger );
             fail( "Expect validation failure for immediate factory component" );
         }
         catch ( ComponentException ce )
@@ -151,13 +154,13 @@
         // immediate is default false if factory is defined
         final ComponentMetadata cm10 = createComponentMetadata( null, "factory" );
         cm10.setService( createServiceMetadata( null ) );
-        cm10.validate();
+        cm10.validate( logger );
         assertFalse( "Component with factory must be delayed", cm10.isImmediate() );
 
         // immediate is false if factory is defined
         final ComponentMetadata cm11 = createComponentMetadata( Boolean.FALSE, "factory" );
         cm11.setService( createServiceMetadata( null ) );
-        cm11.validate();
+        cm11.validate( logger );
         assertFalse( "Component with factory must be delayed", cm11.isImmediate() );
 
         // immediate is default false if factory is defined
@@ -165,7 +168,7 @@
         cm12.setService( createServiceMetadata( null ) );
         try
         {
-            cm12.validate();
+            cm12.validate( logger );
             fail( "Expect validation failure for immediate factory component" );
         }
         catch ( ComponentException ce )
@@ -176,13 +179,13 @@
         // immediate is default false if factory is defined
         final ComponentMetadata cm20 = createComponentMetadata( null, "factory" );
         cm20.setService( createServiceMetadata( Boolean.FALSE ) );
-        cm20.validate();
+        cm20.validate( logger );
         assertFalse( "Component with factory must be delayed", cm20.isImmediate() );
 
         // immediate is false if factory is defined
         final ComponentMetadata cm21 = createComponentMetadata( Boolean.FALSE, "factory" );
         cm21.setService( createServiceMetadata( Boolean.FALSE ) );
-        cm21.validate();
+        cm21.validate( logger );
         assertFalse( "Component with factory must be delayed", cm21.isImmediate() );
 
         // immediate is default false if factory is defined
@@ -190,7 +193,7 @@
         cm22.setService( createServiceMetadata( Boolean.FALSE ) );
         try
         {
-            cm22.validate();
+            cm22.validate( logger );
             fail( "Expect validation failure for immediate factory component" );
         }
         catch ( ComponentException ce )
@@ -203,7 +206,7 @@
         cm30.setService( createServiceMetadata( Boolean.TRUE ) );
         try
         {
-            cm30.validate();
+            cm30.validate( logger );
             fail( "Expect validation failure for factory component with service factory" );
         }
         catch ( ComponentException ce )
@@ -216,7 +219,7 @@
         cm31.setService( createServiceMetadata( Boolean.TRUE ) );
         try
         {
-            cm31.validate();
+            cm31.validate( logger );
             fail( "Expect validation failure for factory component with service factory" );
         }
         catch ( ComponentException ce )
@@ -229,7 +232,7 @@
         cm32.setService( createServiceMetadata( Boolean.TRUE ) );
         try
         {
-            cm32.validate();
+            cm32.validate( logger );
             fail( "Expect validation failure for immediate factory component with service factory" );
         }
         catch ( ComponentException ce )
@@ -240,6 +243,24 @@
     }
 
 
+    public void testReference()
+    {
+        // two references, should validate
+        final ComponentMetadata cm1 = createComponentMetadata( Boolean.TRUE, null );
+        cm1.addDependency( createReferenceMetadata( "name1" ) );
+        cm1.addDependency( createReferenceMetadata( "name2" ) );
+        cm1.validate( logger );
+
+        // two references, must warn
+        final ComponentMetadata cm2 = createComponentMetadata( Boolean.TRUE, null );
+        cm2.addDependency( createReferenceMetadata( "name1" ) );
+        cm2.addDependency( createReferenceMetadata( "name1" ) );
+        cm2.validate( logger );
+        assertTrue( "Expected warning for duplicate reference name", logger.lastMessage != null
+            && logger.lastMessage.indexOf( "Detected duplicate reference name" ) >= 0 );
+    }
+
+
     private ComponentMetadata createComponentMetadata( Boolean immediate, String factory )
     {
         ComponentMetadata meta = new ComponentMetadata();
@@ -267,4 +288,24 @@
         }
         return meta;
     }
+
+
+    private ReferenceMetadata createReferenceMetadata( String name )
+    {
+        ReferenceMetadata meta = new ReferenceMetadata();
+        meta.setName( name );
+        meta.setInterface( "place.holder" );
+        return meta;
+    }
+
+    private static class TestLogger implements Logger
+    {
+        String lastMessage;
+
+
+        public void log( int level, String message, ComponentMetadata metadata, Throwable ex )
+        {
+            lastMessage = message;
+        }
+    }
 }