Add test case exposing FELIX-4977

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1693285 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java b/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
index 061a94b..cdc1cb5 100644
--- a/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
@@ -22,13 +22,15 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import junit.framework.TestCase;
-
 import org.apache.felix.framework.ServiceRegistrationImpl.ServiceReferenceImpl;
 import org.apache.felix.framework.ServiceRegistry.ServiceHolder;
 import org.apache.felix.framework.ServiceRegistry.UsageCount;
@@ -49,6 +51,8 @@
 import org.osgi.framework.hooks.service.FindHook;
 import org.osgi.framework.hooks.service.ListenerHook;
 
+import junit.framework.TestCase;
+
 public class ServiceRegistryTest extends TestCase
 {
     public void testRegisterEventHookService()
@@ -65,6 +69,7 @@
         ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         EventHook hook = new EventHook()
         {
+            @Override
             public void event(ServiceEvent event, Collection contexts)
             {
             }
@@ -133,6 +138,7 @@
         ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         FindHook hook = new FindHook()
         {
+            @Override
             public void find(BundleContext context, String name, String filter,
                 boolean allServices, Collection references)
             {
@@ -201,10 +207,12 @@
         ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         ListenerHook hook = new ListenerHook()
         {
+            @Override
             public void added(Collection listeners)
             {
             }
 
+            @Override
             public void removed(Collection listener)
             {
             }
@@ -272,23 +280,28 @@
         ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         class CombinedService implements ListenerHook, FindHook, EventHook, Runnable
         {
+            @Override
             public void added(Collection listeners)
             {
             }
 
+            @Override
             public void removed(Collection listener)
             {
             }
 
+            @Override
             public void find(BundleContext context, String name, String filter,
                     boolean allServices, Collection references)
             {
             }
 
+            @Override
             public void event(ServiceEvent event, Collection contexts)
             {
             }
 
+            @Override
             public void run()
             {
             }
@@ -1033,6 +1046,110 @@
         assertSame(uc2, inUseMap.get(b)[0]);
     }
 
+    public void testGetUngetServiceFactory() throws Exception
+    {
+        final ServiceRegistry sr = new ServiceRegistry(null, null);
+        final Bundle regBundle = Mockito.mock(Bundle.class);
+        final ServiceRegistration<?> reg = sr.registerService(regBundle, new String[] {Observer.class.getName()},
+                new ServiceFactory<Observer>()
+                {
+
+                    final class ObserverImpl implements Observer
+                    {
+
+                        public volatile boolean active = true;
+
+                        @Override
+                        public void update(Observable o, Object arg)
+                        {
+                            if ( !active )
+                            {
+                                throw new IllegalArgumentException();
+                            }
+                        }
+
+                    };
+
+                    @Override
+                    public Observer getService(Bundle bundle, ServiceRegistration<Observer> registration)
+                    {
+                        return new ObserverImpl();
+                    }
+
+                    @Override
+                    public void ungetService(Bundle bundle, ServiceRegistration<Observer> registration, Observer service)
+                    {
+                        ((ObserverImpl)service).active = false;
+                    }
+                }, null);
+
+        final Bundle clientBundle = Mockito.mock(Bundle.class);
+        Mockito.when(clientBundle.getBundleId()).thenReturn(42L);
+
+        // check simple get/unget
+        final Object obj = sr.getService(clientBundle, reg.getReference(), false);
+        assertNotNull(obj);
+        assertTrue(obj instanceof Observer);
+        ((Observer)obj).update(null, null);
+        sr.ungetService(clientBundle, reg.getReference(), null);
+        try {
+            ((Observer)obj).update(null, null);
+            fail();
+        }
+        catch ( final IllegalArgumentException iae)
+        {
+            // expected
+        }
+
+        // start three threads
+        final int MAX_THREADS = 3;
+        final int MAX_LOOPS = 50000;
+        final CountDownLatch latch = new CountDownLatch(MAX_THREADS);
+        final Thread[] threads = new Thread[MAX_THREADS];
+        final List<Exception> exceptions = Collections.synchronizedList(new ArrayList<Exception>());
+        for(int i=0; i<MAX_THREADS; i++)
+        {
+            threads[i] = new Thread(new Runnable()
+            {
+
+                @Override
+                public void run()
+                {
+                    try
+                    {
+                        Thread.currentThread().sleep(50);
+                    }
+                    catch (InterruptedException e1)
+                    {
+                        // ignore
+                    }
+                    for(int i=0; i < MAX_LOOPS; i++)
+                    {
+                        try
+                        {
+                            final Object obj = sr.getService(clientBundle, reg.getReference(), false);
+                            ((Observer)obj).update(null, null);
+                            sr.ungetService(clientBundle, reg.getReference(), null);
+                        }
+                        catch ( final Exception e)
+                        {
+                            exceptions.add(e);
+                        }
+                    }
+                    latch.countDown();
+                }
+            });
+        }
+        for(int i=0; i<MAX_THREADS; i++)
+        {
+            threads[i].start();
+        }
+
+        latch.await();
+
+        assertTrue("" + exceptions.size(), exceptions.isEmpty());
+    }
+
     private Object getPrivateField(Object obj, String fieldName) throws NoSuchFieldException,
             IllegalAccessException
     {