FELIX-4505 : [Core R6] Support Prototype Service Factory

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1615093 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
index 436dcc5..ed0f52b 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
@@ -20,10 +20,12 @@
 
 import java.io.File;
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Dictionary;
+import java.util.List;
 
 import org.apache.felix.framework.ext.FelixBundleContext;
 import org.osgi.framework.AdminPermission;
@@ -467,25 +469,20 @@
            ((SecurityManager) sm).checkPermission(new ServicePermission(ref, ServicePermission.GET));
         }
 
-        return m_felix.getService(m_bundle, ref);
+        return m_felix.getService(m_bundle, ref, false);
     }
 
     public boolean ungetService(ServiceReference<?> ref)
     {
         checkValidity();
 
-        // CONCURRENCY NOTE: This is a check-then-act situation,
-        // but we ignore it since the time window is small and
-        // the result is the same as if the calling thread had
-        // won the race condition.
-
         if (ref == null)
         {
             throw new NullPointerException("Specified service reference cannot be null.");
         }
 
         // Unget the specified service.
-        return m_felix.ungetService(m_bundle, ref);
+        return m_felix.ungetService(m_bundle, ref, null);
     }
 
     public File getDataFile(String s)
@@ -531,7 +528,14 @@
      */
     public <S> ServiceObjects<S> getServiceObjects(final ServiceReference<S> ref)
     {
-        return new ServiceObjectsImpl(ref);
+    	checkValidity();
+        ServiceRegistrationImpl reg =
+                ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getRegistration();
+        if ( reg.isValid() )
+        {
+        	return new ServiceObjectsImpl(ref);
+        }
+        return null;
     }
 
     //
@@ -541,30 +545,89 @@
     {
         private final ServiceReference<S> m_ref;
 
+        private final List<S> srvObjects = new ArrayList<S>();
+        
         public ServiceObjectsImpl(final ServiceReference<S> ref)
         {
             this.m_ref = ref;
         }
 
         public S getService() {
+        	S srvObj = null;
             // special handling for prototype scope
             if ( m_ref.getProperty(Constants.SERVICE_SCOPE) == Constants.SCOPE_PROTOTYPE )
             {
-                throw new UnsupportedOperationException();
+                checkValidity();
+
+                // CONCURRENCY NOTE: This is a check-then-act situation,
+                // but we ignore it since the time window is small and
+                // the result is the same as if the calling thread had
+                // won the race condition.
+
+                Object sm = System.getSecurityManager();
+
+                if (sm != null)
+                {
+                   ((SecurityManager) sm).checkPermission(new ServicePermission(m_ref, ServicePermission.GET));
+                }
+
+                srvObj = m_felix.getService(m_bundle, m_ref, true);
+            } 
+            else 
+            {
+            	// getService handles singleton and bundle scope
+            	srvObj = BundleContextImpl.this.getService(m_ref);
             }
-            // getService handles singleton and bundle scope
-            return BundleContextImpl.this.getService(m_ref);
+            
+            if ( srvObj != null )
+            {
+            	synchronized ( srvObjects )
+            	{
+            		srvObjects.add(srvObj);
+            	}
+            } 
+            
+            return srvObj;
         }
 
-        public void ungetService(final S service)
+        public void ungetService(final S srvObj)
         {
+        	if ( srvObj != null )
+        	{
+                // check if this object was returned by this service objects
+                synchronized ( srvObjects ) 
+                {
+	                boolean found = false;
+	                int i = 0;
+	                while ( !found && i < srvObjects.size() ) 
+	                {
+	                	found = srvObjects.get(i) == srvObj;
+	                	i++;
+	                }
+	                if ( !found ) 
+	                {
+	                	throw new IllegalArgumentException();	                	
+	                }
+	                srvObjects.remove(i-1);
+                }
+        		
+        	}
             // special handling for prototype scope
             if ( m_ref.getProperty(Constants.SERVICE_SCOPE) == Constants.SCOPE_PROTOTYPE )
             {
-                throw new UnsupportedOperationException();
+                checkValidity();
+
+                // Unget the specified service.
+                if ( !m_felix.ungetService(m_bundle, m_ref, srvObj) ) 
+                {
+                	throw new IllegalArgumentException();
+                }
             }
-            // ungetService handles singleton and bundle scope
-            BundleContextImpl.this.ungetService(m_ref);
+            else
+            {
+                // ungetService handles singleton and bundle scope
+                BundleContextImpl.this.ungetService(m_ref);
+            }
         }
 
         public ServiceReference<S> getServiceReference()
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index f04bac7..280bc85 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -1278,7 +1278,7 @@
                     Collection<Bundle> shrinkableCollisionCandidates = new ShrinkableCollection<Bundle>(collisionCanditates);
                     for (ServiceReference<CollisionHook> hook : hooks)
                     {
-                        CollisionHook ch = getFramework().getService(getFramework(), hook);
+                        CollisionHook ch = getFramework().getService(getFramework(), hook, false);
                         if (ch != null)
                         {
                             int operationType;
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index 8d2a967..2c4336d 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -591,7 +591,7 @@
 
     private static List<Wire> asWireList(List wires)
     {
-        return (List<Wire>) wires;
+        return wires;
     }
 
     public List<Wire> getProvidedResourceWires(String namespace)
@@ -706,7 +706,7 @@
             // enabled; otherwise, create it directly.
             try
             {
-                Constructor ctor = (Constructor) BundleRevisionImpl.getSecureAction()
+                Constructor ctor = BundleRevisionImpl.getSecureAction()
                     .getConstructor(clazz, new Class[] { BundleWiringImpl.class, ClassLoader.class });
                 m_classLoader = (BundleClassLoader)
                     BundleRevisionImpl.getSecureAction().invoke(ctor,
@@ -1521,11 +1521,11 @@
                                 + m_revision.getSymbolicName()
                                 + " is no longer valid.");
                         }
-                        result = (Object) ((BundleClassLoader) cl).findClass(name);
+                        result = ((BundleClassLoader) cl).findClass(name);
                     }
                     else
                     {
-                        result = (Object) m_revision.getResourceLocal(name);
+                        result = m_revision.getResourceLocal(name);
                     }
 
                     // If still not found, then try the revision's dynamic imports.
@@ -1883,6 +1883,7 @@
             m_isParallel = registered;
         }
 
+        @Override
         protected boolean isParallel()
         {
             return m_isParallel;
@@ -2087,7 +2088,7 @@
                                 // Note that we don't use the bundle context
                                 // to get the service object since that would
                                 // perform sercurity checks.
-                                WeavingHook wh = felix.getService(felix, sr);
+                                WeavingHook wh = felix.getService(felix, sr, false);
                                 if (wh != null)
                                 {
                                     try
@@ -2115,7 +2116,7 @@
                                     }
                                     finally
                                     {
-                                        felix.ungetService(felix, sr);
+                                        felix.ungetService(felix, sr, null);
                                     }
                                 }
                             }
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index cf3d073..fa2c129 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -3070,7 +3070,7 @@
                 bundles = new ShrinkableCollection<Bundle>(bundles);
                 for (ServiceReference<org.osgi.framework.hooks.bundle.FindHook> hook : hooks)
                 {
-                    org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook);
+                    org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook, false);
                     if (fh != null)
                     {
                         try
@@ -3156,7 +3156,7 @@
             bundles = new ShrinkableCollection<Bundle>(bundles);
             for (ServiceReference<org.osgi.framework.hooks.bundle.FindHook> hook : hooks)
             {
-                org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook);
+                org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook, false);
                 if (fh != null)
                 {
                     try
@@ -3224,7 +3224,7 @@
             bundles = new ShrinkableCollection<Bundle>(new ArrayList(bundles));
             for (ServiceReference<org.osgi.framework.hooks.bundle.FindHook> hook : hooks)
             {
-                org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook);
+                org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook, false);
                 if (fh != null)
                 {
                     try
@@ -3298,7 +3298,7 @@
                     ServiceListener.class, l, oldFilter, null, true));
             for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
             {
-                org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
+                org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr, false);
                 if (lh != null)
                 {
                     try
@@ -3312,7 +3312,7 @@
                     }
                     finally
                     {
-                        m_registry.ungetService(this, sr);
+                        m_registry.ungetService(this, sr, null);
                     }
                 }
             }
@@ -3324,7 +3324,7 @@
                 ServiceListener.class, l, newFilter, null, false));
         for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
         {
-            org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
+            org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr, false);
             if (lh != null)
             {
                 try
@@ -3338,7 +3338,7 @@
                 }
                 finally
                 {
-                    m_registry.ungetService(this, sr);
+                    m_registry.ungetService(this, sr, null);
                 }
             }
         }
@@ -3365,7 +3365,7 @@
             Collection removed = Collections.singleton(listener);
             for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
             {
-                org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
+                org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr, false);
                 if (lh != null)
                 {
                     try
@@ -3379,7 +3379,7 @@
                     }
                     finally
                     {
-                        m_registry.ungetService(this, sr);
+                        m_registry.ungetService(this, sr, null);
                     }
                 }
             }
@@ -3454,7 +3454,7 @@
         {
             org.osgi.framework.hooks.service.ListenerHook lh =
                 (org.osgi.framework.hooks.service.ListenerHook)
-                    getService(this, reg.getReference());
+                    getService(this, reg.getReference(), false);
             if (lh != null)
             {
                 try
@@ -3469,7 +3469,7 @@
                 }
                 finally
                 {
-                    m_registry.ungetService(this, reg.getReference());
+                    m_registry.ungetService(this, reg.getReference(), null);
                 }
             }
         }
@@ -3534,7 +3534,7 @@
             m_registry.getHooks(org.osgi.framework.hooks.service.FindHook.class);
         for (ServiceReference<org.osgi.framework.hooks.service.FindHook> sr : findHooks)
         {
-            org.osgi.framework.hooks.service.FindHook fh = getService(this, sr);
+            org.osgi.framework.hooks.service.FindHook fh = getService(this, sr, false);
             if (fh != null)
             {
                 try
@@ -3554,7 +3554,7 @@
                 }
                 finally
                 {
-                    m_registry.ungetService(this, sr);
+                    m_registry.ungetService(this, sr, null);
                 }
             }
         }
@@ -3616,11 +3616,11 @@
 
     }
 
-    <S> S getService(Bundle bundle, ServiceReference<S> ref)
+    <S> S getService(Bundle bundle, ServiceReference<S> ref, boolean isPrototype)
     {
         try
         {
-            return m_registry.getService(bundle, ref);
+            return m_registry.getService(bundle, ref, isPrototype);
         }
         catch (ServiceException ex)
         {
@@ -3630,9 +3630,9 @@
         return null;
     }
 
-    boolean ungetService(Bundle bundle, ServiceReference ref)
+    boolean ungetService(Bundle bundle, ServiceReference ref, Object srvObj)
     {
-        return m_registry.ungetService(bundle, ref);
+        return m_registry.ungetService(bundle, ref, srvObj);
     }
 
     File getDataFile(BundleImpl bundle, String s)
diff --git a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java
index e6509ce..715158f 100644
--- a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java
@@ -20,6 +20,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+
 import org.osgi.framework.AdminPermission;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -50,9 +51,10 @@
         m_registry = registry;
     }
 
+    @SuppressWarnings("unchecked")
     void start()
     {
-        m_slReg = m_registry.registerService(m_felix._getBundleContext(),
+        m_slReg = (ServiceRegistration<StartLevel>) m_registry.registerService(m_felix._getBundleContext(),
                 new String[] { StartLevel.class.getName() },
                 new StartLevelImpl(m_felix),
                 null);
@@ -235,7 +237,7 @@
                 // Start thread if necessary.
                 startThread();
                 // Synchronously persists the start level.
-                ((BundleImpl) m_bundle).setStartLevel(startlevel);
+                m_bundle.setStartLevel(startlevel);
                 // Queue request.
                 m_requestListeners.add(null);
                 m_requests.add(new Object[] { m_bundle, new Integer(startlevel) });
diff --git a/framework/src/main/java/org/apache/felix/framework/FrameworkWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/FrameworkWiringImpl.java
index ba51e43..5789947 100644
--- a/framework/src/main/java/org/apache/felix/framework/FrameworkWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/FrameworkWiringImpl.java
@@ -49,9 +49,10 @@
         m_registry = registry;
     }
 
+    @SuppressWarnings("unchecked")
     void start()
     {
-        m_paReg = m_registry.registerService(m_felix._getBundleContext(),
+        m_paReg = (ServiceRegistration<PackageAdmin>) m_registry.registerService(m_felix._getBundleContext(),
                 new String[] { PackageAdmin.class.getName() },
                 new PackageAdminImpl(m_felix),
                 null);
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
index 46c880b..f820a56 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
@@ -18,7 +18,17 @@
  */
 package org.apache.felix.framework;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.WeakHashMap;
 
 import org.apache.felix.framework.capabilityset.CapabilitySet;
 import org.apache.felix.framework.capabilityset.SimpleFilter;
@@ -38,21 +48,21 @@
     private final Logger m_logger;
     private long m_currentServiceId = 1L;
     // Maps bundle to an array of service registrations.
-    private final Map m_regsMap = Collections.synchronizedMap(new HashMap());
+    private final Map<Bundle, ServiceRegistration<?>[]> m_regsMap = Collections.synchronizedMap(new HashMap<Bundle, ServiceRegistration<?>[]>());
     // Capability set for all service registrations.
     private final CapabilitySet m_regCapSet;
 
     // Maps registration to thread to keep track when a
     // registration is in use, which will cause other
     // threads to wait.
-    private final Map m_lockedRegsMap = new HashMap();
+    private final Map<ServiceRegistration<?>, Object> m_lockedRegsMap = new HashMap<ServiceRegistration<?>, Object>();
     // Maps bundle to an array of usage counts.
-    private final Map m_inUseMap = new HashMap();
+    private final Map<Bundle, UsageCount[]> m_inUseMap = new HashMap<Bundle, UsageCount[]>();
 
     private final ServiceRegistryCallbacks m_callbacks;
 
-    private final WeakHashMap<ServiceReference, ServiceReference> m_blackList =
-        new WeakHashMap<ServiceReference, ServiceReference>();
+    private final WeakHashMap<ServiceReference<?>, ServiceReference<?>> m_blackList =
+        new WeakHashMap<ServiceReference<?>, ServiceReference<?>>();
 
     private final static Class<?>[] m_hookClasses = {
         org.osgi.framework.hooks.bundle.CollisionHook.class,
@@ -80,12 +90,12 @@
         m_regCapSet = new CapabilitySet(indices, false);
     }
 
-    public ServiceReference[] getRegisteredServices(Bundle bundle)
+    public ServiceReference<?>[] getRegisteredServices(Bundle bundle)
     {
-        ServiceRegistration[] regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+        ServiceRegistration<?>[] regs = m_regsMap.get(bundle);
         if (regs != null)
         {
-            List refs = new ArrayList(regs.length);
+            List<Object> refs = new ArrayList<Object>(regs.length);
             for (int i = 0; i < regs.length; i++)
             {
                 try
@@ -97,13 +107,13 @@
                     // Don't include the reference as it is not valid anymore
                 }
             }
-            return (ServiceReference[]) refs.toArray(new ServiceReference[refs.size()]);
+            return refs.toArray(new ServiceReference[refs.size()]);
         }
         return null;
     }
 
     // Caller is expected to fire REGISTERED event.
-    public ServiceRegistration registerService(
+    public ServiceRegistration<?> registerService(
         BundleContext context, String[] classNames, Object svcObj, Dictionary dict)
     {
         ServiceRegistrationImpl reg = null;
@@ -120,7 +130,7 @@
             addHooks(classNames, svcObj, reg.getReference());
 
             // Get the bundles current registered services.
-            ServiceRegistration[] regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+            ServiceRegistration<?>[] regs = m_regsMap.get(bundle);
             m_regsMap.put(bundle, addServiceRegistration(regs, reg));
             m_regCapSet.addCapability((BundleCapabilityImpl) reg.getReference());
         }
@@ -128,7 +138,7 @@
         return reg;
     }
 
-    public void unregisterService(Bundle bundle, ServiceRegistration reg)
+    public void unregisterService(Bundle bundle, ServiceRegistration<?> reg)
     {
         // If this is a hook, it should be removed.
         removeHook(reg.getReference());
@@ -142,7 +152,7 @@
             // new bundles will be able to look up the service.
 
             // Now remove the registered service.
-            ServiceRegistration[] regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+            ServiceRegistration<?>[] regs = m_regsMap.get(bundle);
             m_regsMap.put(bundle, removeServiceRegistration(regs, reg));
             m_regCapSet.removeCapability((BundleCapabilityImpl) reg.getReference());
         }
@@ -155,20 +165,32 @@
         }
 
         // Now forcibly unget the service object for all stubborn clients.
-        ServiceReference ref = reg.getReference();
+        ServiceReference<?> ref = reg.getReference();
         Bundle[] clients = getUsingBundles(ref);
         for (int i = 0; (clients != null) && (i < clients.length); i++)
         {
-            while (ungetService(clients[i], reg.getReference()))
-                ; // Keep removing until it is no longer possible
+            UsageCount[] usages = m_inUseMap.get(clients[i]);
+            for (int x = 0; (usages != null) && (x < usages.length); x++)
+            {
+                if (usages[x].m_ref.equals(ref))
+                {
+                	ungetService(clients[i], ref, (usages[x].m_prototype ? usages[x].m_svcObj : null));
+                }
+            }
         }
         // Invalidate registration
         ((ServiceRegistrationImpl) reg).invalidate();
         // Bundles are allowed to get a reference while unregistering
         for (int i = 0; (clients != null) && (i < clients.length); i++)
         {
-            while (ungetService(clients[i], ref))
-                ; // Keep removing until it is no longer possible
+            UsageCount[] usages = m_inUseMap.get(clients[i]);
+            for (int x = 0; (usages != null) && (x < usages.length); x++)
+            {
+                if (usages[x].m_ref.equals(ref))
+                {
+                	ungetService(clients[i], ref, (usages[x].m_prototype ? usages[x].m_svcObj : null));
+                }
+            }
         }
     }
 
@@ -182,10 +204,10 @@
     public void unregisterServices(Bundle bundle)
     {
         // Simply remove all service registrations for the bundle.
-        ServiceRegistration[] regs = null;
+        ServiceRegistration<?>[] regs = null;
         synchronized (this)
         {
-            regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+            regs = m_regsMap.get(bundle);
         }
 
         // Note, there is no race condition here with respect to the
@@ -231,7 +253,7 @@
         else if ((className != null) && (filter != null))
         {
             // Return services matching the class name and filter.
-            List filters = new ArrayList(2);
+            List<SimpleFilter> filters = new ArrayList<SimpleFilter>(2);
             filters.add(new SimpleFilter(Constants.OBJECTCLASS, className, SimpleFilter.EQ));
             filters.add(filter);
             filter = new SimpleFilter(null, filters, SimpleFilter.AND);
@@ -240,15 +262,15 @@
 
         Set<BundleCapability> matches = m_regCapSet.match(filter, false);
 
-        return new ArrayList(matches);
+        return new ArrayList<BundleCapability>(matches);
     }
 
-    public synchronized ServiceReference[] getServicesInUse(Bundle bundle)
+    public synchronized ServiceReference<?>[] getServicesInUse(Bundle bundle)
     {
-        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        UsageCount[] usages = m_inUseMap.get(bundle);
         if (usages != null)
         {
-            ServiceReference[] refs = new ServiceReference[usages.length];
+            ServiceReference<?>[] refs = new ServiceReference[usages.length];
             for (int i = 0; i < refs.length; i++)
             {
                 refs[i] = usages[i].m_ref;
@@ -258,7 +280,8 @@
         return null;
     }
 
-    public <S> S getService(Bundle bundle, ServiceReference<S> ref)
+    @SuppressWarnings("unchecked")
+    public <S> S getService(Bundle bundle, ServiceReference<S> ref, boolean isPrototype)
     {
         UsageCount usage = null;
         Object svcObj = null;
@@ -299,14 +322,15 @@
             if (reg.isValid())
             {
                 // Get the usage count, if any.
-                usage = getUsageCount(bundle, ref);
+                // if prototype, we always create a new usage
+                usage = isPrototype ? null : getUsageCount(bundle, ref, null);
 
                 // If we don't have a usage count, then create one and
                 // since the spec says we increment usage count before
                 // actually getting the service object.
                 if (usage == null)
                 {
-                    usage = addUsageCount(bundle, ref);
+                    usage = addUsageCount(bundle, ref, isPrototype);
                 }
 
                 // Increment the usage count and grab the already retrieved
@@ -340,7 +364,7 @@
                 // unregistered while we didn't hold the lock.
                 if (!reg.isValid() || (svcObj == null))
                 {
-                    flushUsageCount(bundle, ref);
+                    flushUsageCount(bundle, ref, usage);
                 }
                 else
                 {
@@ -354,7 +378,7 @@
         return (S) svcObj;
     }
 
-    public boolean ungetService(Bundle bundle, ServiceReference ref)
+    public boolean ungetService(Bundle bundle, ServiceReference<?> ref, Object svcObj)
     {
         UsageCount usage = null;
         ServiceRegistrationImpl reg =
@@ -384,7 +408,7 @@
             }
 
             // Get the usage count.
-            usage = getUsageCount(bundle, ref);
+            usage = getUsageCount(bundle, ref, svcObj);
             // If there is no cached services, then just return immediately.
             if (usage == null)
             {
@@ -424,7 +448,7 @@
                 if (!reg.isValid() || (usage.m_count <= 0))
                 {
                     usage.m_svcObj = null;
-                    flushUsageCount(bundle, ref);
+                    flushUsageCount(bundle, ref, usage);
                 }
 
                 // Release the registration lock so any waiting threads can
@@ -448,7 +472,7 @@
         UsageCount[] usages;
         synchronized (this)
         {
-            usages = (UsageCount[]) m_inUseMap.get(bundle);
+            usages = m_inUseMap.get(bundle);
         }
 
         if (usages == null)
@@ -466,21 +490,21 @@
         for (int i = 0; i < usages.length; i++)
         {
             // Keep ungetting until all usage count is zero.
-            while (ungetService(bundle, usages[i].m_ref))
+            while (ungetService(bundle, usages[i].m_ref, usages[i].m_prototype ? usages[i].m_svcObj : null))
             {
                 // Empty loop body.
             }
         }
     }
 
-    public synchronized Bundle[] getUsingBundles(ServiceReference ref)
+    public synchronized Bundle[] getUsingBundles(ServiceReference<?> ref)
     {
         Bundle[] bundles = null;
-        for (Iterator iter = m_inUseMap.entrySet().iterator(); iter.hasNext(); )
+        for (Iterator<Map.Entry<Bundle, UsageCount[]>> iter = m_inUseMap.entrySet().iterator(); iter.hasNext(); )
         {
-            Map.Entry entry = (Map.Entry) iter.next();
-            Bundle bundle = (Bundle) entry.getKey();
-            UsageCount[] usages = (UsageCount[]) entry.getValue();
+            Map.Entry<Bundle, UsageCount[]> entry = iter.next();
+            Bundle bundle = entry.getKey();
+            UsageCount[] usages = entry.getValue();
             for (int useIdx = 0; useIdx < usages.length; useIdx++)
             {
                 if (usages[useIdx].m_ref.equals(ref))
@@ -503,7 +527,7 @@
         return bundles;
     }
 
-    void servicePropertiesModified(ServiceRegistration reg, Dictionary oldProps)
+    void servicePropertiesModified(ServiceRegistration<?> reg, Dictionary oldProps)
     {
         updateHook(reg.getReference());
         if (m_callbacks != null)
@@ -518,8 +542,8 @@
         return m_logger;
     }
 
-    private static ServiceRegistration[] addServiceRegistration(
-        ServiceRegistration[] regs, ServiceRegistration reg)
+    private static ServiceRegistration<?>[] addServiceRegistration(
+        ServiceRegistration<?>[] regs, ServiceRegistration<?> reg)
     {
         if (regs == null)
         {
@@ -527,7 +551,7 @@
         }
         else
         {
-            ServiceRegistration[] newRegs = new ServiceRegistration[regs.length + 1];
+            ServiceRegistration<?>[] newRegs = new ServiceRegistration[regs.length + 1];
             System.arraycopy(regs, 0, newRegs, 0, regs.length);
             newRegs[regs.length] = reg;
             regs = newRegs;
@@ -535,8 +559,8 @@
         return regs;
     }
 
-    private static ServiceRegistration[] removeServiceRegistration(
-        ServiceRegistration[] regs, ServiceRegistration reg)
+    private static ServiceRegistration<?>[] removeServiceRegistration(
+        ServiceRegistration<?>[] regs, ServiceRegistration<?> reg)
     {
         for (int i = 0; (regs != null) && (i < regs.length); i++)
         {
@@ -550,7 +574,7 @@
                 // Otherwise, we need to do some array copying.
                 else
                 {
-                    ServiceRegistration[] newRegs = new ServiceRegistration[regs.length - 1];
+                    ServiceRegistration<?>[] newRegs = new ServiceRegistration[regs.length - 1];
                     System.arraycopy(regs, 0, newRegs, 0, i);
                     if (i < newRegs.length)
                     {
@@ -571,12 +595,14 @@
      * @param ref The service reference to find in the bundle's usage counts.
      * @return The associated usage count or null if not found.
     **/
-    private UsageCount getUsageCount(Bundle bundle, ServiceReference ref)
+    private UsageCount getUsageCount(Bundle bundle, ServiceReference<?> ref, final Object svcObj)
     {
-        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        UsageCount[] usages = m_inUseMap.get(bundle);
         for (int i = 0; (usages != null) && (i < usages.length); i++)
         {
-            if (usages[i].m_ref.equals(ref))
+            if (usages[i].m_ref.equals(ref) 
+               && ((svcObj == null && !usages[i].m_prototype) 
+            		|| (usages[i].m_svcObj == svcObj && usages[i].m_prototype)))
             {
                 return usages[i];
             }
@@ -594,12 +620,13 @@
      * @param ref The service reference of the acquired service.
      * @param svcObj The service object of the acquired service.
     **/
-    private UsageCount addUsageCount(Bundle bundle, ServiceReference ref)
+    private UsageCount addUsageCount(Bundle bundle, ServiceReference<?> ref, boolean isPrototype)
     {
-        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        UsageCount[] usages = m_inUseMap.get(bundle);
 
         UsageCount usage = new UsageCount();
         usage.m_ref = ref;
+        usage.m_prototype = isPrototype;
 
         if (usages == null)
         {
@@ -630,12 +657,12 @@
      * @param bundle The bundle whose usage count should be removed.
      * @param ref The service reference whose usage count should be removed.
     **/
-    private void flushUsageCount(Bundle bundle, ServiceReference ref)
+    private void flushUsageCount(Bundle bundle, ServiceReference<?> ref, UsageCount uc)
     {
-        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        UsageCount[] usages = m_inUseMap.get(bundle);
         for (int i = 0; (usages != null) && (i < usages.length); i++)
         {
-            if (usages[i].m_ref.equals(ref))
+            if ((uc == null && usages[i].m_ref.equals(ref)) || (uc == usages[i]))
             {
                 // If this is the only usage, then point to empty list.
                 if ((usages.length - 1) == 0)
@@ -653,6 +680,7 @@
                             usages, i + 1, newUsages, i, newUsages.length - i);
                     }
                     usages = newUsages;
+                    i--;
                 }
             }
         }
@@ -671,12 +699,12 @@
     // Hook-related methods.
     //
 
-    boolean isHookBlackListed(ServiceReference sr)
+    boolean isHookBlackListed(ServiceReference<?> sr)
     {
         return m_blackList.containsKey(sr);
     }
 
-    void blackListHook(ServiceReference sr)
+    void blackListHook(ServiceReference<?> sr)
     {
         m_blackList.put(sr, sr);
     }
@@ -731,7 +759,7 @@
         }
     }
 
-    private void updateHook(ServiceReference ref)
+    private void updateHook(ServiceReference<?> ref)
     {
         // We maintain the hooks sorted, so if ranking has changed for example,
         // we need to ensure the order remains correct by resorting the hooks.
@@ -757,7 +785,7 @@
         }
     }
 
-    private void removeHook(ServiceReference ref)
+    private void removeHook(ServiceReference<?> ref)
     {
         Object svcObj = ((ServiceRegistrationImpl.ServiceReferenceImpl) ref)
             .getRegistration().getService();
@@ -790,25 +818,26 @@
             Set<ServiceReference<?>> hooks = m_allHooks.get(hookClass);
             if (hooks != null)
             {
-                SortedSet sorted = new TreeSet<ServiceReference<?>>(Collections.reverseOrder());
+                SortedSet<ServiceReference<?>> sorted = new TreeSet<ServiceReference<?>>(Collections.reverseOrder());
                 sorted.addAll(hooks);
                 return asTypedSortedSet(sorted);
             }
-            return Collections.EMPTY_SET;
+            return Collections.emptySet();
         }
     }
 
     private static <S> SortedSet<ServiceReference<S>> asTypedSortedSet(
         SortedSet<ServiceReference<?>> ss)
     {
-        return (SortedSet<ServiceReference<S>>) (SortedSet) ss;
+        return (SortedSet) ss;
     }
 
     private static class UsageCount
     {
-        public int m_count = 0;
-        public ServiceReference m_ref = null;
-        public Object m_svcObj = null;
+        public int m_count;
+        public ServiceReference<?> m_ref;
+        public Object m_svcObj;
+        public boolean m_prototype;
     }
 
     public interface ServiceRegistryCallbacks
diff --git a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
index 6c6e75f..0270af8 100644
--- a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
@@ -31,6 +31,7 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.StringTokenizer;
+
 import org.apache.felix.framework.capabilityset.CapabilitySet;
 import org.apache.felix.framework.capabilityset.SimpleFilter;
 import org.apache.felix.framework.resolver.CandidateComparator;
@@ -41,7 +42,6 @@
 import org.apache.felix.framework.util.ShrinkableCollection;
 import org.apache.felix.framework.util.Util;
 import org.apache.felix.framework.util.manifestparser.R4Library;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
 import org.apache.felix.framework.wiring.BundleRequirementImpl;
 import org.apache.felix.framework.wiring.BundleWireImpl;
 import org.osgi.framework.Bundle;
@@ -566,7 +566,7 @@
         throws BundleException
     {
         // This map maps the hook factory service to the actual hook objects. It
-        // needs to be a map that preserves insertion order to ensure that we call 
+        // needs to be a map that preserves insertion order to ensure that we call
         // hooks in the correct order.
         // The hooks are added in the order that m_felix.getHooks() returns them which
         // is also the order in which they should be called.
@@ -595,13 +595,13 @@
             triggers = Collections.unmodifiableSet(triggers);
 
             BundleException rethrow = null;
-            
+
             // Create resolver hook objects by calling begin() on factory.
             for (ServiceReference<ResolverHookFactory> ref : hookRefs)
             {
                 try
                 {
-                    ResolverHookFactory rhf = m_felix.getService(m_felix, ref);
+                    ResolverHookFactory rhf = m_felix.getService(m_felix, ref, false);
                     if (rhf != null)
                     {
                         ResolverHook hook =
@@ -621,7 +621,7 @@
                         ex);
                     // Resolver hook spec: if there is an exception during the resolve operation; abort.
                     // So we break here to make sure that no further resolver hooks are created.
-                    break; 
+                    break;
                 }
             }
 
@@ -663,7 +663,7 @@
                         ex);
                     // Resolver hook spec: if there is an exception during the resolve operation; abort.
                     // So we break here to make sure that no further resolver operations are executed.
-                    break; 
+                    break;
                 }
             }
 
@@ -751,7 +751,7 @@
                 {
                     invalid = true;
                 }
-                m_felix.ungetService(m_felix, ref);
+                m_felix.ungetService(m_felix, ref, null);
             }
             if (invalid)
             {
@@ -824,7 +824,7 @@
             {
                 BundleCapability cap = itCand.next();
                 if (CapabilitySet.matches(
-                    (BundleCapabilityImpl) cap,
+                    cap,
                     ((BundleRequirementImpl) dynamics.get(dynIdx)).getFilter()))
                 {
                     dynReq = (BundleRequirementImpl) dynamics.get(dynIdx);
@@ -841,7 +841,7 @@
             {
                 BundleCapability cap = itCand.next();
                 if (!CapabilitySet.matches(
-                    (BundleCapabilityImpl) cap, dynReq.getFilter()))
+                    cap, dynReq.getFilter()))
                 {
                     itCand.remove();
                 }
@@ -1570,7 +1570,7 @@
     {
         final Map<ServiceReference<ResolverHookFactory>, ResolverHook> m_resolveHookMap;
         final Collection<BundleRevision> m_brWhitelist;
- 
+
         /** The map passed in must be of an ordered type, so that the iteration order over the values
          * is predictable.
          */
@@ -1580,8 +1580,8 @@
             m_resolveHookMap = resolveHookMap;
             m_brWhitelist = brWhiteList;
         }
-        
-        Collection<BundleRevision> getBundleRevisionWhitelist() 
+
+        Collection<BundleRevision> getBundleRevisionWhitelist()
         {
             return m_brWhitelist;
         }
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersActivator.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersActivator.java
index 4eca450..d8dea4a 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersActivator.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersActivator.java
@@ -19,8 +19,6 @@
 package org.apache.felix.framework;
 
 import java.net.ContentHandler;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 
@@ -29,7 +27,6 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.url.URLStreamHandlerService;
-import org.osgi.util.tracker.ServiceTracker;
 
 /**
  * <p>
@@ -107,13 +104,13 @@
                     {
                         if (value.equals(((String[]) values)[valueIdx]))
                         {
-                            return m_framework.getService(m_framework, ref);
+                            return m_framework.getService(m_framework, ref, false);
                         }
                     }
                 }
                 else if (value.equals(values))
                 {
-                    return m_framework.getService(m_framework, ref);
+                    return m_framework.getService(m_framework, ref, false);
                 }
             }
         }
diff --git a/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java b/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
index c5c264c..fe6d0ad 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
@@ -585,7 +585,7 @@
                     new ShrinkableCollection(new ArrayList(entry.getValue()));
                 shrinkableMap.put(
                     entry.getKey(),
-                    (Collection<ListenerHook.ListenerInfo>) shrinkableCollection);
+                    shrinkableCollection);
             }
             shrinkableMap =
                 new ShrinkableMap<BundleContext, Collection<ListenerHook.ListenerInfo>>
@@ -598,7 +598,7 @@
                     org.osgi.framework.hooks.service.EventListenerHook elh = null;
                     try
                     {
-                        elh = m_registry.getService(felix, sr);
+                        elh = m_registry.getService(felix, sr, false);
                     }
                     catch (Exception ex)
                     {
@@ -618,7 +618,7 @@
                         }
                         finally
                         {
-                            m_registry.ungetService(felix, sr);
+                            m_registry.ungetService(felix, sr, null);
                         }
                     }
                 }
@@ -675,7 +675,7 @@
                     T eh = null;
                     try
                     {
-                        eh = m_registry.getService(felix, sr);
+                        eh = m_registry.getService(felix, sr, false);
                     }
                     catch (Exception ex)
                     {
@@ -705,7 +705,7 @@
                         }
                         finally
                         {
-                            m_registry.ungetService(felix, sr);
+                            m_registry.ungetService(felix, sr, null);
                         }
                     }
                 }
diff --git a/framework/src/test/java/org/apache/felix/framework/CollisionHookTest.java b/framework/src/test/java/org/apache/felix/framework/CollisionHookTest.java
index 31eafd0..63496a5 100644
--- a/framework/src/test/java/org/apache/felix/framework/CollisionHookTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/CollisionHookTest.java
@@ -66,7 +66,7 @@
         {
             differentBundle, identicalBundle
         });
-        Mockito.when(felixMock.getService(felixMock, chRef)).thenReturn(testCollisionHook);
+        Mockito.when(felixMock.getService(felixMock, chRef, false)).thenReturn(testCollisionHook);
 
         // Mock the archive of the bundle being installed
         Map<String, String> headerMap = new HashMap<String, String>();
@@ -129,7 +129,7 @@
         {
             differentBundle, identicalBundle
         });
-        Mockito.when(felixMock.getService(felixMock, chRef)).thenReturn(testCollisionHook);
+        Mockito.when(felixMock.getService(felixMock, chRef, false)).thenReturn(testCollisionHook);
 
         // Mock the archive of the bundle being installed
         Map<String, String> headerMap = new HashMap<String, String>();
@@ -185,7 +185,7 @@
         {
             differentBundle, identicalBundle
         });
-        Mockito.when(felixMock.getService(felixMock, chRef)).thenReturn(testCollisionHook);
+        Mockito.when(felixMock.getService(felixMock, chRef, false)).thenReturn(testCollisionHook);
 
         // Mock the archive of the bundle being installed
         Map<String, String> headerMap = new HashMap<String, String>();