Refactor ServiceReferenceImpl to be an inner class of ServiceRegistrationImpl. This makes it easier to call the registration directly where needed and fixes an IllegalStateException that could happen in hashCode and equals (FELIX-892).

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@736124 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceReferenceImpl.java b/framework/src/main/java/org/apache/felix/framework/ServiceReferenceImpl.java
deleted file mode 100644
index 9f444c9..0000000
--- a/framework/src/main/java/org/apache/felix/framework/ServiceReferenceImpl.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.felix.framework;
-
-import org.apache.felix.framework.util.Util;
-import org.apache.felix.moduleloader.IModule;
-import org.apache.felix.moduleloader.IWire;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
-
-class ServiceReferenceImpl implements ServiceReference
-{
-    private ServiceRegistrationImpl m_registration = null;
-    private Bundle m_bundle = null;
-
-    public ServiceReferenceImpl(ServiceRegistrationImpl reg, Bundle bundle)
-    {
-        m_registration = reg;
-        m_bundle = bundle;
-    }
-
-    protected ServiceRegistrationImpl getServiceRegistration()
-    {
-        return m_registration;
-    }
-
-    public Object getProperty(String s)
-    {
-        return m_registration.getProperty(s);
-    }
-
-    public String[] getPropertyKeys()
-    {
-        return m_registration.getPropertyKeys();
-    }
-
-    public Bundle getBundle()
-    {
-        // The spec says that this should return null if
-        // the service is unregistered.
-        return (m_registration.isValid()) ? m_bundle : null;
-    }
-
-    public Bundle[] getUsingBundles()
-    {
-        return m_registration.getUsingBundles();
-    }
-
-    public boolean equals(Object obj)
-    {
-        try
-        {
-            ServiceReferenceImpl ref = (ServiceReferenceImpl) obj;
-            return ref.m_registration == m_registration;
-        }
-        catch (ClassCastException ex)
-        {
-            // Ignore and return false.
-        }
-        catch (NullPointerException ex)
-        {
-            // Ignore and return false.
-        }
-
-        return false;
-    }
-
-    public int hashCode()
-    {
-        if (m_registration.getReference() != null)
-        {
-            if (m_registration.getReference() != this)
-            {
-                return m_registration.getReference().hashCode();
-            }
-            return super.hashCode();
-        }
-        return 0;
-    }
-
-    public String toString()
-    {
-        String[] ocs = (String[]) getProperty("objectClass");
-        String oc = "[";
-        for(int i = 0; i < ocs.length; i++)
-        {
-            oc = oc + ocs[i];
-            if (i < ocs.length - 1)
-                oc = oc + ", ";
-        }
-        oc = oc + "]";
-        return oc;
-    }
-
-    public boolean isAssignableTo(Bundle requester, String className)
-    {
-        // Always return true if the requester is the same as the provider.
-        if (requester == m_bundle)
-        {
-            return true;
-        }
-
-        // Boolean flag.
-        boolean allow = true;
-        // Get the package.
-        String pkgName =
-            Util.getClassPackage(className);
-        IModule requesterModule = ((BundleImpl) requester).getCurrentModule();
-        // Get package wiring from service requester.
-        IWire requesterWire = Util.getWire(requesterModule, pkgName);
-
-        // There are three situations that may occur here:
-        //   1. The requester does not have a wire for the package.
-        //   2. The provider does not have a wire for the package.
-        //   3. Both have a wire for the package.
-        // For case 1, we do not filter the service reference since we
-        // assume that the bundle is using reflection or that it won't
-        // use that class at all since it does not import it. For
-        // case 2, we have to try to load the class from the class
-        // loader of the service object and then compare the class
-        // loaders to determine if we should filter the service
-        // refernce. In case 3, we simply compare the exporting
-        // modules from the package wiring to determine if we need
-        // to filter the service reference.
-
-        // Case 1: Always include service reference.
-        if (requesterWire == null)
-        {
-            return allow;
-        }
-
-        // Get package wiring from service provider.
-        IModule providerModule = ((BundleImpl) m_bundle).getCurrentModule();
-        IWire providerWire = Util.getWire(providerModule, pkgName);
-        
-        // Case 2: Only include service reference if the service
-        // object uses the same class as the requester.
-        if (providerWire == null)
-        {
-            // If the provider is not the exporter of the requester's package,
-            // then try to use the service registration to see if the requester's
-            // class is accessible.
-            if (!((BundleImpl) m_bundle).hasModule(requesterWire.getExporter()))
-            {
-                try
-                {
-                    // Load the class from the requesting bundle.
-                    Class requestClass = requesterModule.getClassByDelegation(className);
-                    // Get the service registration and ask it to check
-                    // if the service object is assignable to the requesting
-                    // bundle's class.
-                    allow = getServiceRegistration().isClassAccessible(requestClass);
-                }
-                catch (Exception ex)
-                {
-                    // This should not happen, filter to be safe.
-                    allow = false;
-                }
-            }
-            else
-            {
-                // O.k. the provider is the exporter of the requester's package, now check
-                // if the requester is wired to the latest version of the provider, if so
-                // then allow else don't (the provider has been updated but not refreshed).
-                allow = providerModule == requesterWire.getExporter();
-            }
-        }
-        // Case 3: Include service reference if the wires have the
-        // same source module.
-        else
-        {
-            allow = providerWire.getExporter().equals(requesterWire.getExporter());
-        }
-
-        return allow;
-    }
-
-    public int compareTo(Object reference)
-    {
-        ServiceReference other = (ServiceReference) reference;
-
-        Long id = (Long) getProperty(Constants.SERVICE_ID);
-        Long otherId = (Long) other.getProperty(Constants.SERVICE_ID);
-
-        if (id.equals(otherId))
-        {
-            return 0; // same service
-        }
-
-        Integer rank = (Integer) getProperty(Constants.SERVICE_RANKING);
-        Integer otherRank = (Integer) other.getProperty(Constants.SERVICE_RANKING);
-
-        // If no rank, then spec says it defaults to zero.
-        rank = (rank == null) ? new Integer(0) : rank;
-        otherRank = (otherRank == null) ? new Integer(0) : otherRank;
-
-        // Sort by rank in ascending order.
-        if (rank.compareTo(otherRank) < 0)
-        {
-            return -1; // lower rank
-        }
-        else if (rank.compareTo(otherRank) > 0)
-        {
-            return 1; // higher rank
-        }
-
-        // If ranks are equal, then sort by service id in descending order.
-        return (id.compareTo(otherId) < 0) ? 1 : -1;
-    }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
index 47073bb..d1f26b9 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
@@ -24,6 +24,8 @@
 
 import org.apache.felix.framework.util.StringMap;
 import org.apache.felix.framework.util.Util;
+import org.apache.felix.moduleloader.IModule;
+import org.apache.felix.moduleloader.IWire;
 import org.osgi.framework.*;
 
 class ServiceRegistrationImpl implements ServiceRegistration
@@ -67,7 +69,7 @@
         // Since all reference to this service are supposed to
         // be equal, we use the hashcode of this reference for
         // a references to this service in ServiceReference.
-        m_ref = new ServiceReferenceImpl(this, m_bundle);
+        m_ref = new ServiceReferenceImpl();
     }
 
     protected synchronized boolean isValid()
@@ -318,4 +320,166 @@
             return null;
         }
     }
+    
+    class ServiceReferenceImpl implements ServiceReference
+    {
+        private ServiceReferenceImpl() {}
+    
+        ServiceRegistrationImpl getServiceRegistration()
+        {
+            return ServiceRegistrationImpl.this;
+        }
+
+        public Object getProperty(String s)
+        {
+            return ServiceRegistrationImpl.this.getProperty(s);
+        }
+
+        public String[] getPropertyKeys()
+        {
+            return ServiceRegistrationImpl.this.getPropertyKeys();
+        }
+
+        public Bundle getBundle()
+        {
+            // The spec says that this should return null if
+            // the service is unregistered.
+            return (isValid()) ? m_bundle : null;
+        }
+
+        public Bundle[] getUsingBundles()
+        {
+            return ServiceRegistrationImpl.this.getUsingBundles();
+        }
+
+        public String toString()
+        {
+            String[] ocs = (String[]) getProperty("objectClass");
+            String oc = "[";
+            for(int i = 0; i < ocs.length; i++)
+            {
+                oc = oc + ocs[i];
+                if (i < ocs.length - 1)
+                    oc = oc + ", ";
+            }
+            oc = oc + "]";
+            return oc;
+        }
+
+        public boolean isAssignableTo(Bundle requester, String className)
+        {
+            // Always return true if the requester is the same as the provider.
+            if (requester == m_bundle)
+            {
+                return true;
+            }
+
+            // Boolean flag.
+            boolean allow = true;
+            // Get the package.
+            String pkgName =
+                Util.getClassPackage(className);
+            IModule requesterModule = ((BundleImpl) requester).getCurrentModule();
+            // Get package wiring from service requester.
+            IWire requesterWire = Util.getWire(requesterModule, pkgName);
+
+            // There are three situations that may occur here:
+            //   1. The requester does not have a wire for the package.
+            //   2. The provider does not have a wire for the package.
+            //   3. Both have a wire for the package.
+            // For case 1, we do not filter the service reference since we
+            // assume that the bundle is using reflection or that it won't
+            // use that class at all since it does not import it. For
+            // case 2, we have to try to load the class from the class
+            // loader of the service object and then compare the class
+            // loaders to determine if we should filter the service
+            // refernce. In case 3, we simply compare the exporting
+            // modules from the package wiring to determine if we need
+            // to filter the service reference.
+
+            // Case 1: Always include service reference.
+            if (requesterWire == null)
+            {
+                return allow;
+            }
+
+            // Get package wiring from service provider.
+            IModule providerModule = ((BundleImpl) m_bundle).getCurrentModule();
+            IWire providerWire = Util.getWire(providerModule, pkgName);
+            
+            // Case 2: Only include service reference if the service
+            // object uses the same class as the requester.
+            if (providerWire == null)
+            {
+                // If the provider is not the exporter of the requester's package,
+                // then try to use the service registration to see if the requester's
+                // class is accessible.
+                if (!((BundleImpl) m_bundle).hasModule(requesterWire.getExporter()))
+                {
+                    try
+                    {
+                        // Load the class from the requesting bundle.
+                        Class requestClass = requesterModule.getClassByDelegation(className);
+                        // Get the service registration and ask it to check
+                        // if the service object is assignable to the requesting
+                        // bundle's class.
+                        allow = getServiceRegistration().isClassAccessible(requestClass);
+                    }
+                    catch (Exception ex)
+                    {
+                        // This should not happen, filter to be safe.
+                        allow = false;
+                    }
+                }
+                else
+                {
+                    // O.k. the provider is the exporter of the requester's package, now check
+                    // if the requester is wired to the latest version of the provider, if so
+                    // then allow else don't (the provider has been updated but not refreshed).
+                    allow = providerModule == requesterWire.getExporter();
+                }
+            }
+            // Case 3: Include service reference if the wires have the
+            // same source module.
+            else
+            {
+                allow = providerWire.getExporter().equals(requesterWire.getExporter());
+            }
+
+            return allow;
+        }
+
+        public int compareTo(Object reference)
+        {
+            ServiceReference other = (ServiceReference) reference;
+
+            Long id = (Long) getProperty(Constants.SERVICE_ID);
+            Long otherId = (Long) other.getProperty(Constants.SERVICE_ID);
+
+            if (id.equals(otherId))
+            {
+                return 0; // same service
+            }
+
+            Integer rank = (Integer) getProperty(Constants.SERVICE_RANKING);
+            Integer otherRank = (Integer) other.getProperty(Constants.SERVICE_RANKING);
+
+            // If no rank, then spec says it defaults to zero.
+            rank = (rank == null) ? new Integer(0) : rank;
+            otherRank = (otherRank == null) ? new Integer(0) : otherRank;
+
+            // Sort by rank in ascending order.
+            if (rank.compareTo(otherRank) < 0)
+            {
+                return -1; // lower rank
+            }
+            else if (rank.compareTo(otherRank) > 0)
+            {
+                return 1; // higher rank
+            }
+
+            // If ranks are equal, then sort by service id in descending order.
+            return (id.compareTo(otherId) < 0) ? 1 : -1;
+        }
+    }
 }
\ No newline at end of file
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 03e87b0..6bb1727 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
@@ -228,7 +228,7 @@
         Object svcObj = null;
 
         // Get the service registration.
-        ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
+        ServiceRegistrationImpl reg = ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getServiceRegistration();
 
         synchronized (this)
         {
@@ -337,7 +337,7 @@
     public boolean ungetService(Bundle bundle, ServiceReference ref)
     {
         UsageCount usage = null;
-        ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
+        ServiceRegistrationImpl reg = ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getServiceRegistration();
 
         synchronized (this)
         {
@@ -402,7 +402,7 @@
             if (usage.m_count == 0)
             {
                 // Remove reference from usages array.
-                ((ServiceReferenceImpl) ref)
+                ((ServiceRegistrationImpl.ServiceReferenceImpl) ref)
                     .getServiceRegistration().ungetService(bundle, usage.m_svcObj);
                 usage.m_svcObj = null;
             }