FELIX-2679 : Detect AnnotationTagProvider's through META-INF/services

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1029812 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/annotations/src/main/resources/META-INF/services/org.apache.felix.scrplugin.tags.annotation.AnnotationTagProvider b/scrplugin/annotations/src/main/resources/META-INF/services/org.apache.felix.scrplugin.tags.annotation.AnnotationTagProvider
new file mode 100644
index 0000000..a9f2add
--- /dev/null
+++ b/scrplugin/annotations/src/main/resources/META-INF/services/org.apache.felix.scrplugin.tags.annotation.AnnotationTagProvider
@@ -0,0 +1,2 @@
+org.apache.felix.scrplugin.tags.annotation.defaulttag.DefaultAnnotationTagProvider
+org.apache.felix.scrplugin.tags.annotation.sling.SlingAnnotationTagProvider
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java
index 8320269..957521d 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/JavaClassDescriptorManager.java
@@ -14,14 +14,9 @@
 package org.apache.felix.scrplugin;
 
 
-import java.io.File;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
 import java.util.*;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
+import java.util.jar.*;
 
 import org.apache.felix.scrplugin.om.Component;
 import org.apache.felix.scrplugin.om.Components;
@@ -31,6 +26,7 @@
 import org.apache.felix.scrplugin.tags.cl.ClassLoaderJavaClassDescription;
 import org.apache.felix.scrplugin.tags.qdox.QDoxJavaClassDescription;
 import org.apache.felix.scrplugin.xml.ComponentDescriptorIO;
+
 import com.thoughtworks.qdox.JavaDocBuilder;
 import com.thoughtworks.qdox.model.JavaClass;
 import com.thoughtworks.qdox.model.JavaSource;
@@ -86,7 +82,7 @@
         this.processAnnotations = processAnnotations;
         this.parseJavadocs = parseJavadocs;
         this.log = log;
-        this.annotationTagProviderManager = new AnnotationTagProviderManager( annotationTagProviders );
+        this.annotationTagProviderManager = new AnnotationTagProviderManager( log, annotationTagProviders, classLoader );
         this.classloader = classLoader;
 
         ClassUtil.classLoader = this.classloader;
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationTagProviderManager.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationTagProviderManager.java
index cd3f9d9..74b8300 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationTagProviderManager.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/tags/annotation/AnnotationTagProviderManager.java
@@ -19,9 +19,13 @@
 package org.apache.felix.scrplugin.tags.annotation;
 
 
-import java.util.ArrayList;
-import java.util.List;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.util.*;
 
+import javax.imageio.spi.ServiceRegistry;
+
+import org.apache.felix.scrplugin.Log;
 import org.apache.felix.scrplugin.SCRDescriptorFailureException;
 import org.apache.felix.scrplugin.tags.JavaField;
 import org.apache.felix.scrplugin.tags.JavaTag;
@@ -43,36 +47,97 @@
      * that provide mappings from custom annotations to
      * {@link org.apache.felix.scrplugin.tags.JavaTag} implementations.
      */
-    private final List<AnnotationTagProvider> annotationTagProviders = new ArrayList<AnnotationTagProvider>();
+    private final Map<String, AnnotationTagProvider> annotationTagProviders = new LinkedHashMap<String, AnnotationTagProvider>();
 
+    private final Log log;
 
     /**
      * @param annotationTagProviderClasses List of classes that implements
      *            {@link AnnotationTagProvider} interface.
      * @throws SCRDescriptorFailureException
      */
-    public AnnotationTagProviderManager( String[] annotationTagProviderClasses ) throws SCRDescriptorFailureException
+    public AnnotationTagProviderManager( final Log log,
+            final String[] annotationTagProviderClasses,
+            final ClassLoader classLoader )
+    throws SCRDescriptorFailureException
     {
+        this.log = log;
 
-        // the classloader used to load the provider classes
-        final ClassLoader classLoader = getClass().getClassLoader();
-
-        // always add provider supporting built-in SCR default properties
-        loadProvider( annotationTagProviders, classLoader,
-            "org.apache.felix.scrplugin.tags.annotation.defaulttag.DefaultAnnotationTagProvider", true );
-        loadProvider( annotationTagProviders, classLoader,
-            "org.apache.felix.scrplugin.tags.annotation.sling.SlingAnnotationTagProvider", true );
+        // search for providers
+        final Iterator<AnnotationTagProvider> serviceIter = ServiceRegistry.lookupProviders(AnnotationTagProvider.class, classLoader);
+        while ( serviceIter.hasNext() )
+        {
+            final AnnotationTagProvider provider = serviceIter.next();
+            this.addProvider(provider, false);
+        }
 
         // add custom providers defined in pom
         for ( int i = 0; i < annotationTagProviderClasses.length; i++ )
         {
-            loadProvider( annotationTagProviders, classLoader, annotationTagProviderClasses[i], false );
+            loadProvider( classLoader, annotationTagProviderClasses[i], false );
+        }
+
+        // always add provider supporting built-in SCR default properties (for compatibility with older
+        // annotation versions)
+        loadProvider( classLoader,
+            "org.apache.felix.scrplugin.tags.annotation.defaulttag.DefaultAnnotationTagProvider", true );
+        loadProvider( classLoader,
+            "org.apache.felix.scrplugin.tags.annotation.sling.SlingAnnotationTagProvider", true );
+    }
+
+    /**
+     * Try to get the location (class loader) from the object.
+     */
+    private String getLocation(final Object obj)
+    {
+        try {
+            final ProtectionDomain pd = obj.getClass().getProtectionDomain();
+            if ( pd != null && pd.getCodeSource() != null )
+            {
+                final CodeSource cs = pd.getCodeSource();
+                if ( cs.getLocation() != null )
+                {
+                    return cs.getLocation().toExternalForm();
+                }
+            }
+        }
+        catch (final SecurityException se)
+        {
+            // ignore this
+        }
+        // by default return the class laoder
+        return obj.getClass().getClassLoader().toString();
+    }
+
+    /**
+     * Add a provider (if not already available)
+     */
+    private void addProvider(final AnnotationTagProvider provider, final boolean silent)
+    {
+        // check if this provider is already loaded
+        final String key = provider.getClass().getName();
+        if ( !this.annotationTagProviders.containsKey(key) )
+        {
+            this.annotationTagProviders.put(key, provider);
+        }
+        else
+        {
+            if ( !silent )
+            {
+                // now check if the location of the providers (classloader) is different
+                // and log a warning
+                final AnnotationTagProvider usedProvider = this.annotationTagProviders.get(key);
+                if ( !usedProvider.equals(provider) )
+                {
+                    this.log.warn("Ignoring provider " + provider + " from location " + getLocation(provider) +
+                            ". Using previously found version from " + getLocation(usedProvider));
+                }
+
+            }
         }
     }
 
-
-    private static void loadProvider( final List<AnnotationTagProvider> annotationTagProviders,
-        final ClassLoader classLoader, final String className, final boolean silent )
+    private void loadProvider( final ClassLoader classLoader, final String className, final boolean silent )
         throws SCRDescriptorFailureException
     {
         String failureMessage = null;
@@ -81,7 +146,7 @@
             Class<?> clazz = classLoader.loadClass( className );
             try
             {
-                annotationTagProviders.add( ( AnnotationTagProvider ) clazz.newInstance() );
+                addProvider( ( AnnotationTagProvider ) clazz.newInstance(), silent );
             }
             catch ( ClassCastException e )
             {
@@ -135,7 +200,7 @@
     {
         List<JavaTag> tags = new ArrayList<JavaTag>();
 
-        for ( AnnotationTagProvider provider : this.annotationTagProviders )
+        for ( AnnotationTagProvider provider : this.annotationTagProviders.values() )
         {
             tags.addAll( provider.getTags( annotation, description, field ) );
         }
diff --git a/scrplugin/maven-scr-plugin/pom.xml b/scrplugin/maven-scr-plugin/pom.xml
index 7c8bbb0..353689d 100644
--- a/scrplugin/maven-scr-plugin/pom.xml
+++ b/scrplugin/maven-scr-plugin/pom.xml
@@ -60,12 +60,6 @@
             <version>0.0.1-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
-            <version>1.3.1-SNAPSHOT</version>
-            <scope>compile</scope>
-        </dependency>
     </dependencies>
     
     <build>
diff --git a/scrplugin/scrtask/pom.xml b/scrplugin/scrtask/pom.xml
index 99687cf..935e5b0 100644
--- a/scrplugin/scrtask/pom.xml
+++ b/scrplugin/scrtask/pom.xml
@@ -57,12 +57,6 @@
             <version>0.0.1-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
-            <version>1.3.1-SNAPSHOT</version>
-            <scope>compile</scope>
-        </dependency>
     </dependencies>
     
     <build>