FELIX-3731 Support multi-value service.pid properties
FELIX-3732 Register service.pid's of ManagedServiceFactory services as factory PIDs (instead of service PIDs).


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1401858 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java b/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java
index 1e2dc85..4ff1fad 100644
--- a/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java
+++ b/metatype/src/main/java/org/apache/felix/metatype/internal/ServiceMetaTypeInformation.java
@@ -19,7 +19,15 @@
 package org.apache.felix.metatype.internal;
 
 
-import org.osgi.framework.*;
+import java.util.Collection;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.log.LogService;
 import org.osgi.service.metatype.MetaTypeProvider;
 
@@ -35,6 +43,10 @@
 public class ServiceMetaTypeInformation extends MetaTypeInformationImpl implements ServiceListener
 {
 
+    private static final String MANAGED_SERVICE = "org.osgi.service.cm.ManagedService";
+
+    private static final String MANAGED_SERVICE_FACTORY = "org.osgi.service.cm.ManagedServiceFactory";
+
     /**
      * The filter specification to find <code>ManagedService</code>s and
      * <code>ManagedServiceFactory</code>s as well as to register a service
@@ -43,7 +55,8 @@
      * We use the hard coded class name here to not create a dependency on the
      * ConfigurationAdmin service, which may not be available.
      */
-    private static final String FILTER = "(|(objectClass=org.osgi.service.cm.ManagedService)(objectClass=org.osgi.service.cm.ManagedServiceFactory))";
+    private static final String FILTER = "(|(objectClass=" + MANAGED_SERVICE + ")(objectClass="
+        + MANAGED_SERVICE_FACTORY + "))";
 
     /**
      * The <code>BundleContext</code> used to get and unget services which
@@ -105,6 +118,13 @@
     }
 
 
+    void dispose()
+    {
+        this.bundleContext.removeServiceListener( this );
+        super.dispose();
+    }
+
+
     // ---------- ServiceListener ----------------------------------------------
 
     /**
@@ -160,21 +180,27 @@
             String factoryPid = ( String ) serviceRef.getProperty( SERVICE_FACTORYPID );
             if ( factoryPid != null )
             {
-                addFactoryPids( new String[]
-                    { factoryPid } );
-                addMetaTypeProvider( factoryPid, mtp );
+                addFactoryMetaTypeProvider( new String[]
+                    { factoryPid }, mtp );
                 ungetService = false;
             }
             else
             {
                 // 2. check for a service PID
-                String pid = ( String ) serviceRef.getProperty( Constants.SERVICE_PID );
-                if ( pid != null )
+                String[] pids = getServicePids( serviceRef );
+                if ( pids != null )
                 {
-                    addPids( new String[]
-                        { pid } );
-                    addMetaTypeProvider( pid, mtp );
-                    ungetService = false;
+                    if ( isService( serviceRef, MANAGED_SERVICE ) )
+                    {
+                        addSingletonMetaTypeProvider( pids, mtp );
+                        ungetService = false;
+                    }
+
+                    if ( isService( serviceRef, MANAGED_SERVICE_FACTORY ) )
+                    {
+                        addFactoryMetaTypeProvider( pids, mtp );
+                        ungetService = false;
+                    }
                 }
             }
         }
@@ -208,17 +234,24 @@
         String factoryPid = ( String ) serviceRef.getProperty( SERVICE_FACTORYPID );
         if ( factoryPid != null )
         {
-            ungetService = removeMetaTypeProvider( factoryPid ) != null;
-            removeFactoryPid( factoryPid );
+            ungetService = removeFactoryMetaTypeProvider( new String[]
+                { factoryPid } );
         }
         else
         {
             // 2. check for a service PID
-            String pid = ( String ) serviceRef.getProperty( Constants.SERVICE_PID );
-            if ( pid != null )
+            String[] pids = getServicePids( serviceRef );
+            if ( pids != null )
             {
-                ungetService = removeMetaTypeProvider( pid ) != null;
-                removePid( pid );
+                if ( isService( serviceRef, MANAGED_SERVICE ) )
+                {
+                    ungetService |= removeSingletonMetaTypeProvider( pids );
+                }
+
+                if ( isService( serviceRef, MANAGED_SERVICE_FACTORY ) )
+                {
+                    ungetService |= removeFactoryMetaTypeProvider( pids );
+                }
             }
         }
 
@@ -228,4 +261,62 @@
             bundleContext.ungetService( serviceRef );
         }
     }
+
+
+    static String[] getServicePids( final ServiceReference ref )
+    {
+        return getStringPlus( ref, Constants.SERVICE_PID );
+    }
+
+
+    static String[] getStringPlus( final ServiceReference ref, final String propertyName )
+    {
+        final String[] res;
+        Object prop = ref.getProperty( propertyName );
+        if ( prop == null )
+        {
+            res = null;
+        }
+        else if ( prop instanceof String )
+        {
+            res = new String[]
+                { ( String ) prop };
+        }
+        else if ( prop instanceof Collection )
+        {
+            final Object[] col = ( ( Collection ) prop ).toArray();
+            res = new String[col.length];
+            for ( int i = 0; i < res.length; i++ )
+            {
+                res[i] = String.valueOf( col[i] );
+            }
+        }
+        else if ( prop.getClass().isArray() && String.class.equals( prop.getClass().getComponentType() ) )
+        {
+            res = ( String[] ) prop;
+        }
+        else // unsupported type of property
+        {
+            res = null;
+        }
+
+        return res;
+    }
+
+
+    static boolean isService( final ServiceReference ref, final String type )
+    {
+        String[] oc = ( String[] ) ref.getProperty( Constants.OBJECTCLASS );
+        if ( oc != null )
+        {
+            for ( int i = 0; i < oc.length; i++ )
+            {
+                if ( oc[i].equals( type ) )
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }