com.tangosol.internal.net.ConfigurableCacheFactorySession Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of coherence Show documentation
Show all versions of coherence Show documentation
Oracle Coherence Community Edition
/*
* 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
{}
}