connect/src/main/java/org/apache/felix/connect/felix/framework/ServiceRegistry.java [627:773]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    UsageCount obtainUsageCount(Bundle bundle, ServiceReference<?> ref, Object svcObj, Boolean isPrototype)
    {
        UsageCount usage = null;

        // This method uses an optimistic concurrency mechanism with a conditional put/replace
        // on the m_inUseMap. If this fails (because another thread made changes) this thread
        // retries the operation. This is the purpose of the while loop.
        boolean success = false;
        while (!success)
        {
            UsageCount[] usages = m_inUseMap.get(bundle);

            // If we know it's a prototype, then we always need to create a new usage count
            if (!Boolean.TRUE.equals(isPrototype))
            {
                for (int i = 0; (usages != null) && (i < usages.length); i++)
                {
                    if (usages[i].m_ref.equals(ref)
                       && ((svcObj == null && !usages[i].m_prototype) || usages[i].getService() == svcObj))
                    {
                        return usages[i];
                    }
                }
            }

            // We haven't found an existing usage count object so we need to create on. For this we need to
            // know whether this is a prototype or not.
            if (isPrototype == null)
            {
                // If this parameter isn't passed in we can't create a usage count.
                return null;
            }

            // Add a new Usage Count.
            usage = new UsageCount(ref, isPrototype);
            if (usages == null)
            {
                UsageCount[] newUsages = new UsageCount[] { usage };
                success = m_inUseMap.putIfAbsent(bundle, newUsages) == null;
            }
            else
            {
                UsageCount[] newUsages = new UsageCount[usages.length + 1];
                System.arraycopy(usages, 0, newUsages, 0, usages.length);
                newUsages[usages.length] = usage;
                success = m_inUseMap.replace(bundle, usages, newUsages);
            }
        }
        return usage;
    }

    /**
     * Utility method to flush the specified bundle's usage count for the
     * specified service reference. This should be called to completely
     * remove the associated usage count object for the specified service
     * reference. If the goal is to simply decrement the usage, then get
     * the usage count and decrement its counter. This method will also
     * remove the specified bundle from the "in use" map if it has no more
     * usage counts after removing the usage count for the specified service
     * reference.
     * @param bundle The bundle whose usage count should be removed.
     * @param ref The service reference whose usage count should be removed.
    **/
    void flushUsageCount(Bundle bundle, ServiceReference<?> ref, UsageCount uc)
    {
        // This method uses an optimistic concurrency mechanism with conditional modifications
        // on the m_inUseMap. If this fails (because another thread made changes) this thread
        // retries the operation. This is the purpose of the while loop.
        boolean success = false;
        while (!success)
        {
            UsageCount[] usages = m_inUseMap.get(bundle);
            final UsageCount[] orgUsages = usages;
            for (int i = 0; (usages != null) && (i < usages.length); i++)
            {
                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)
                    {
                        usages = null;
                    }
                    // Otherwise, we need to do some array copying.
                    else
                    {
                        UsageCount[] newUsages = new UsageCount[usages.length - 1];
                        System.arraycopy(usages, 0, newUsages, 0, i);
                        if (i < newUsages.length)
                        {
                            System.arraycopy(
                                usages, i + 1, newUsages, i, newUsages.length - i);
                        }
                        usages = newUsages;
                        i--;
                    }
                }
            }

            if (usages == orgUsages)
                return; // no change in map

            if (orgUsages != null)
            {
                if (usages != null)
                    success = m_inUseMap.replace(bundle, orgUsages, usages);
                else
                    success = m_inUseMap.remove(bundle, orgUsages);
            }
        }
    }

    public HookRegistry getHookRegistry()
    {
        return this.hookRegistry;
    }

    static class UsageCount
    {
        final ServiceReference<?> m_ref;
        final boolean m_prototype;

        final AtomicLong m_count = new AtomicLong();
        final AtomicLong m_serviceObjectsCount = new AtomicLong();
        final AtomicReference<ServiceHolder> m_svcHolderRef = new AtomicReference<ServiceHolder>();

        UsageCount(final ServiceReference<?> ref, final boolean isPrototype)
        {
            m_ref = ref;
            m_prototype = isPrototype;
        }

        Object getService()
        {
            ServiceHolder sh = m_svcHolderRef.get();
            return sh == null ? null : sh.m_service;
        }
    }

    static class ServiceHolder
    {
        final CountDownLatch m_latch = new CountDownLatch(1);
        volatile Object m_service;
    }

    public interface ServiceRegistryCallbacks
    {
        void serviceChanged(ServiceEvent event, Dictionary<?,?> oldProps);
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java [646:792]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    UsageCount obtainUsageCount(Bundle bundle, ServiceReference<?> ref, Object svcObj, Boolean isPrototype)
    {
        UsageCount usage = null;

        // This method uses an optimistic concurrency mechanism with a conditional put/replace
        // on the m_inUseMap. If this fails (because another thread made changes) this thread
        // retries the operation. This is the purpose of the while loop.
        boolean success = false;
        while (!success)
        {
            UsageCount[] usages = m_inUseMap.get(bundle);

            // If we know it's a prototype, then we always need to create a new usage count
            if (!Boolean.TRUE.equals(isPrototype))
            {
                for (int i = 0; (usages != null) && (i < usages.length); i++)
                {
                    if (usages[i].m_ref.equals(ref)
                       && ((svcObj == null && !usages[i].m_prototype) || usages[i].getService() == svcObj))
                    {
                        return usages[i];
                    }
                }
            }

            // We haven't found an existing usage count object so we need to create on. For this we need to
            // know whether this is a prototype or not.
            if (isPrototype == null)
            {
                // If this parameter isn't passed in we can't create a usage count.
                return null;
            }

            // Add a new Usage Count.
            usage = new UsageCount(ref, isPrototype);
            if (usages == null)
            {
                UsageCount[] newUsages = new UsageCount[] { usage };
                success = m_inUseMap.putIfAbsent(bundle, newUsages) == null;
            }
            else
            {
                UsageCount[] newUsages = new UsageCount[usages.length + 1];
                System.arraycopy(usages, 0, newUsages, 0, usages.length);
                newUsages[usages.length] = usage;
                success = m_inUseMap.replace(bundle, usages, newUsages);
            }
        }
        return usage;
    }

    /**
     * Utility method to flush the specified bundle's usage count for the
     * specified service reference. This should be called to completely
     * remove the associated usage count object for the specified service
     * reference. If the goal is to simply decrement the usage, then get
     * the usage count and decrement its counter. This method will also
     * remove the specified bundle from the "in use" map if it has no more
     * usage counts after removing the usage count for the specified service
     * reference.
     * @param bundle The bundle whose usage count should be removed.
     * @param ref The service reference whose usage count should be removed.
    **/
    void flushUsageCount(Bundle bundle, ServiceReference<?> ref, UsageCount uc)
    {
        // This method uses an optimistic concurrency mechanism with conditional modifications
        // on the m_inUseMap. If this fails (because another thread made changes) this thread
        // retries the operation. This is the purpose of the while loop.
        boolean success = false;
        while (!success)
        {
            UsageCount[] usages = m_inUseMap.get(bundle);
            final UsageCount[] orgUsages = usages;
            for (int i = 0; (usages != null) && (i < usages.length); i++)
            {
                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)
                    {
                        usages = null;
                    }
                    // Otherwise, we need to do some array copying.
                    else
                    {
                        UsageCount[] newUsages = new UsageCount[usages.length - 1];
                        System.arraycopy(usages, 0, newUsages, 0, i);
                        if (i < newUsages.length)
                        {
                            System.arraycopy(
                                usages, i + 1, newUsages, i, newUsages.length - i);
                        }
                        usages = newUsages;
                        i--;
                    }
                }
            }

            if (usages == orgUsages)
                return; // no change in map

            if (orgUsages != null)
            {
                if (usages != null)
                    success = m_inUseMap.replace(bundle, orgUsages, usages);
                else
                    success = m_inUseMap.remove(bundle, orgUsages);
            }
        }
    }

    public HookRegistry getHookRegistry()
    {
        return this.hookRegistry;
    }

    static class UsageCount
    {
        final ServiceReference<?> m_ref;
        final boolean m_prototype;

        final AtomicLong m_count = new AtomicLong();
        final AtomicLong m_serviceObjectsCount = new AtomicLong();
        final AtomicReference<ServiceHolder> m_svcHolderRef = new AtomicReference<ServiceHolder>();

        UsageCount(final ServiceReference<?> ref, final boolean isPrototype)
        {
            m_ref = ref;
            m_prototype = isPrototype;
        }

        Object getService()
        {
            ServiceHolder sh = m_svcHolderRef.get();
            return sh == null ? null : sh.m_service;
        }
    }

    static class ServiceHolder
    {
        final CountDownLatch m_latch = new CountDownLatch(1);
        volatile Object m_service;
    }

    public interface ServiceRegistryCallbacks
    {
        void serviceChanged(ServiceEvent event, Dictionary<?,?> oldProps);
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



