All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.internal.net.ConfigurableCacheFactorySession Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2021, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */
package com.tangosol.internal.net;

import com.oracle.coherence.common.util.Options;

import com.tangosol.net.ConfigurableCacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.net.Session;
import com.tangosol.net.ValueTypeAssertion;
import com.tangosol.net.cache.TypeAssertion;
import com.tangosol.net.topic.NamedTopic;

import com.tangosol.util.Base;
import com.tangosol.util.RegistrationBehavior;
import com.tangosol.util.ResourceRegistry;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * A {@link Session} that uses a specific {@link ConfigurableCacheFactory}
 * and {@link ClassLoader}.
 *
 * @author bo  2015.07.27
 */
public class ConfigurableCacheFactorySession
        implements Session
    {
    // ----- constructors ---------------------------------------------------

    /**
     * Constructs a {@link ConfigurableCacheFactorySession}.
     *
     * @param ccf     the {@link ConfigurableCacheFactory}
     * @param loader  the {@link ClassLoader}
     */
    public ConfigurableCacheFactorySession(ConfigurableCacheFactory ccf, ClassLoader loader)
        {
        m_ccf = ccf;
        m_classLoader = loader == null ? Base.ensureClassLoader(null) : loader;
        m_mapCaches   = new ConcurrentHashMap<>();
        m_mapTopics   = new ConcurrentHashMap<>();
        m_fActive     = true;
        }

    // ----- Session interface ----------------------------------------------

    @Override
    public  NamedCache getCache(String sName, NamedCache.Option... options)
        {
        if (m_fActive)
            {
            ResourceRegistry registry = m_ccf.getResourceRegistry();

            // ensure we have a reference counter for the named cache
            registry.registerResource(
                    NamedCacheReferenceCounter.class, sName,
                    NamedCacheReferenceCounter::new,
                    RegistrationBehavior.IGNORE, null);

            // grab the map of caches organized by the type assertion, creating if necessary
            ConcurrentHashMap mapCachesByTypeAssertion =
                    m_mapCaches.computeIfAbsent(sName,
                                                any -> new ConcurrentHashMap<>());

            // grab the type assertion from the provided options
            Options optionSet = Options.from(NamedCache.Option.class, options);
            TypeAssertion typeAssertion          = optionSet.get(TypeAssertion.class);

            // grab the session-based named cache for the type of assertion, creating one if necessary
            SessionNamedCache cacheSession = mapCachesByTypeAssertion.compute(
                    typeAssertion,
                    (key, value) -> {

                        // only return a valid session-based named cache
                        if (value != null && !value.isDestroyed() && !value.isReleased())
                            {
                            return value;
                            }

                        // request an underlying NamedCache from the CCF
                        NamedCache cacheUnderlying = m_ccf.ensureTypedCache(
                                sName,
                                m_classLoader,
                                typeAssertion);

                        SessionNamedCache cache = new SessionNamedCache<>(this,
                                cacheUnderlying,
                                typeAssertion);

                        // increment the reference count for the underlying NamedCache
                        registry.getResource(NamedCacheReferenceCounter.class,
                                sName).incrementAndGet();

                        return cache;
                    });

            return cacheSession;
            }
        else
            {
            throw new IllegalStateException("Session is closed");
            }
        }


    @Override
    @SuppressWarnings("unchecked")
    public  NamedTopic getTopic(String sName, NamedTopic.Option... options)
        {
        if (m_fActive)
            {
            ResourceRegistry registry = m_ccf.getResourceRegistry();

            // ensure we have a reference counter for the named topic
            registry.registerResource(
                    NamedTopicReferenceCounter.class, sName,
                    NamedTopicReferenceCounter::new,
                    RegistrationBehavior.IGNORE, null);

            // grab the map of topics organized by the type assertion, creating if necessary
            ConcurrentHashMap mapTopicsByTypeAssertion =
                    m_mapTopics.computeIfAbsent(sName, any -> new ConcurrentHashMap<>());

            // grab the type assertion
            Options optionSet     = Options.from(NamedTopic.Option.class, options);
            ValueTypeAssertion      typeAssertion = optionSet.get(ValueTypeAssertion.class);

            // grab the session-based named topic for the type of assertion, creating one if necessary
            return mapTopicsByTypeAssertion.compute(
                    typeAssertion,
                    (key, value) ->
                        {
                        // only return a valid session-based named topic
                        if (value != null && !value.isDestroyed() && !value.isReleased())
                            {
                            return value;
                            }

                        // request an underlying NamedTopic from the CCF
                        NamedTopic topicUnderlying = m_ccf.ensureTopic(sName, m_classLoader, typeAssertion);

                        SessionNamedTopic topic = new SessionNamedTopic<>(this,
                                topicUnderlying,
                                typeAssertion);

                        // increment the reference count for the underlying NamedTopic
                        registry.getResource(NamedTopicReferenceCounter.class, sName).incrementAndGet();

                        return topic;
                        });
            }
        else
            {
            throw new IllegalStateException("Session is closed");
            }
        }

    @Override
    public synchronized void close()
            throws Exception
        {
        if (m_fActive)
            {
            m_fActive = false;

            // close all of the named caches created by this session
            m_mapCaches.values().stream()
                       .flatMap(
                               mapCachesByAssertion -> mapCachesByAssertion.values().stream())
                       .forEach(SessionNamedCache::close);

            // drop the references to caches
            m_mapCaches.clear();

            // close all of the named topics created by this session
            m_mapTopics.values().stream()
                       .flatMap(mapTopicsByAssertion -> mapTopicsByAssertion.values().stream())
                       .forEach(SessionNamedTopic::close);

            // drop the references to topic
            m_mapTopics.clear();
            }
        }

    // ----- ConfigurableCacheFactorySession methods ------------------------

    private void assertActive()
        {
        if (!m_fActive)
            {
            throw new IllegalStateException("Session is closed");
            }
        }

     void onClose(SessionNamedTopic topic)
        {
        dropNamedTopic(topic);

        topic.onClosing();

        // decrement the reference count for the underlying NamedTopic
        ResourceRegistry registry = m_ccf.getResourceRegistry();

        if (registry.getResource(NamedTopicReferenceCounter.class, topic.getName()).decrementAndGet() == 0)
            {
            m_ccf.releaseTopic(topic.getInternalNamedTopic());
            }

        topic.onClosed();
        }

     void onDestroy(SessionNamedTopic topic)
        {
        dropNamedTopic(topic);

        topic.onDestroying();

        // reset the reference count for the underlying NamedCache
        ResourceRegistry registry = m_ccf.getResourceRegistry();

        registry.getResource(NamedTopicReferenceCounter.class, topic.getName()).reset();

        m_ccf.destroyTopic(topic.getInternalNamedTopic());

        topic.onDestroyed();
        }

    @SuppressWarnings({"rawtypes", "SuspiciousMethodCalls"})
     void dropNamedTopic(SessionNamedTopic namedTopic)
        {
        // drop the NamedTopic from this session
        ConcurrentHashMap mapTopicsByTypeAssertion =
                m_mapTopics.get(namedTopic.getName());

        if (mapTopicsByTypeAssertion != null)
            {
            mapTopicsByTypeAssertion.remove(namedTopic.getTypeAssertion());
            }
        }

     void onClose(SessionNamedCache namedCache)
        {
        dropNamedCache(namedCache);

        namedCache.onClosing();

        // decrement the reference count for the underlying NamedCache
        ResourceRegistry registry = m_ccf.getResourceRegistry();

        if (registry.getResource(NamedCacheReferenceCounter.class,
                                 namedCache.getCacheName()).decrementAndGet() == 0)
            {
            m_ccf.releaseCache(namedCache.getInternalNamedCache());
            }

        namedCache.onClosed();
        }

     void onDestroy(SessionNamedCache namedCache)
        {
        dropNamedCache(namedCache);

        namedCache.onDestroying();

        // reset the reference count for the underlying NamedCache
        ResourceRegistry registry = m_ccf.getResourceRegistry();

        registry.getResource(NamedCacheReferenceCounter.class,
                                 namedCache.getCacheName()).reset();

        m_ccf.destroyCache(namedCache.getInternalNamedCache());

        namedCache.onDestroyed();
        }

     void dropNamedCache(SessionNamedCache namedCache)
        {
        // drop the NamedCache from this session
        ConcurrentHashMap mapCachesByTypeAssertion =
                m_mapCaches.get(namedCache.getCacheName());

        if (mapCachesByTypeAssertion != null)
            {
            mapCachesByTypeAssertion.remove(namedCache.getTypeAssertion());
            }
        }

    // ----- data members ---------------------------------------------------

    /**
     * The {@link ConfigurableCacheFactory} on which the {@link Session}
     * is based.
     */
    private ConfigurableCacheFactory m_ccf;

    /**
     * The {@link ClassLoader} for the {@link Session}.
     */
    private ClassLoader m_classLoader;

    /**
     * Is the {@link Session} active / available for use.
     */
    private volatile boolean m_fActive;

    /**
     * The {@link SessionNamedCache}s created by this {@link Session}
     * (so we close them when the session closes).
     */
    private ConcurrentHashMap> m_mapCaches;

    /**
     * The {@link NamedTopic}s created by this {@link Session}
     * (so we close them when the session closes).
     */
    private ConcurrentHashMap> m_mapTopics;

    /**
     * Tracks use of individual  instances by all {@link Session}s
     * against the same {@link ConfigurableCacheFactory} (by using reference counting)
     */
    protected static class ReferenceCounter
        {
        private AtomicInteger count;

        public ReferenceCounter()
            {
            count = new AtomicInteger(0);
            }

        public int get()
            {
            return count.get();
            }

        public int incrementAndGet()
            {
            return count.incrementAndGet();
            }

        public int decrementAndGet()
            {
            return count.decrementAndGet();
            }

        public void reset()
            {
            count.set(0);
            }
        }

    /**
     * Tracks use of individual {@link NamedCache} instances by all {@link Session}s
     * against the same {@link ConfigurableCacheFactory} (by using reference counting)
     */
    protected static class NamedCacheReferenceCounter
            extends ReferenceCounter
        {}

    /**
     * Tracks use of individual {@link NamedTopic} instances by all {@link Session}s
     * against the same {@link ConfigurableCacheFactory} (by using reference counting)
     */
    protected static class NamedTopicReferenceCounter
            extends ReferenceCounter
        {}
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy