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

com.tangosol.coherence.jcache.CoherenceBasedCachingProvider Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2000, 2022, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * https://oss.oracle.com/licenses/upl.
 */
package com.tangosol.coherence.jcache;

import com.oracle.coherence.common.base.Logger;

import com.tangosol.coherence.config.Config;

import com.tangosol.coherence.jcache.localcache.LocalCacheConfiguration;

import com.tangosol.coherence.jcache.partitionedcache.PartitionedCacheConfiguration;
import com.tangosol.coherence.jcache.passthroughcache.PassThroughCacheConfiguration;

import com.tangosol.coherence.jcache.remotecache.RemoteCacheConfiguration;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.ConfigurableCacheFactory;
import com.tangosol.net.ExtensibleConfigurableCacheFactory;

import com.tangosol.util.Base;

import static com.tangosol.coherence.jcache.Constants.DEFAULT_COHERENCE_JCACHE_CONFIGURATION_CLASS_NAME_SYSTEM_PROPERTY;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import java.net.URI;
import java.net.URISyntaxException;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.WeakHashMap;

import java.util.concurrent.atomic.AtomicReference;

import javax.cache.CacheException;
import javax.cache.CacheManager;

import javax.cache.configuration.CompleteConfiguration;
import javax.cache.configuration.Configuration;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.configuration.OptionalFeature;

import javax.cache.spi.CachingProvider;

/**
 * The Coherence-based implementation of a {@link CachingProvider}.
 *
 * Added support to recognize and work within a container environment.
 * Calls to JCache API from container code should call CachingProvider#getCacheManager(null, null, null)
 * in order that container descriptor file coherence-application.xml is used to initialize CacheManager.
 *
 * @author bb  2013.04.08
 * @author bo  2013.12.17
 * @author jf  2014.06.24
 */
public class CoherenceBasedCachingProvider
        implements CachingProvider
    {
    // ----- constructors ---------------------------------------------------

    /**
     * Constructs a {@link CoherenceBasedCachingProvider}.
     */
    public CoherenceBasedCachingProvider()
        {
        m_mapClzldrToMgrMap = new WeakHashMap>();
        }

    // ----- CachingProvider interface --------------------------------------

    /**
     * Return a CacheManager.
     * 

* To get a container managed {@link CacheManager}, any container code calling this method MUST * call this method with a null uri parameter. Calling with a non-null value results in a non-container managed * {@link CacheManager}. Container managed instances are configured via GAR configuration and are created/closed * by container. *

* If this method is called from a container context with a non-null URI, the returned {@link CacheManager} is considered * unmanaged. * * @param u A {@link URI} referencing a coherence cache config containing JCacheNamespace or JCacheExtendNamespace. * A value of null denotes to compute the default URI for this {@link CacheManager}. * @param cl classloader * @param p Coherence JCache implementation specific {@link Properties} * @return {@link CacheManager} */ @Override public synchronized CacheManager getCacheManager(URI u, ClassLoader cl, Properties p) { ExtensibleConfigurableCacheFactory eccf = null; Properties props = (p == null) ? getDefaultProperties() : p; URI uri = (u == null) ? getDefaultURI() : u; ClassLoader cldr = (cl == null) ? getDefaultClassLoader() : cl; HashMap mapUriToMgr = m_mapClzldrToMgrMap.get(cldr); if (mapUriToMgr == null) { mapUriToMgr = new HashMap(); } CacheManager mgr = mapUriToMgr.get(uri); if (mgr == null) { mgr = createCacheMananger(uri, cldr, props); mapUriToMgr.put(uri, mgr); } else { Logger.finest("getCacheManager found existing CacheManager uri=" + uri + " classloader=" + cldr); } if (!m_mapClzldrToMgrMap.containsKey(cldr)) { m_mapClzldrToMgrMap.put(cldr, mapUriToMgr); } return mgr; } /** * Returns a non-null ClassLoader. * * @return a ClassLoader */ @Override public ClassLoader getDefaultClassLoader() { return Base.getContextClassLoader(); } @Override public URI getDefaultURI() { String kind = Config.getProperty(Constants.DEFAULT_COHERENCE_JCACHE_CONFIGURATION_CLASS_NAME_SYSTEM_PROPERTY); boolean fExtendEnabled = isExtendClient(kind); String uri = Config.getProperty(Constants.DEFAULT_COHERENCE_CONFIGURATION_URI_SYSTEM_PROPERTY, fExtendEnabled ? Constants.DEFAULT_COHERENCE_JCACHE_EXTEND_CLIENT_CONFIGURATION_URI : Constants.DEFAULT_COHERENCE_JCACHE_CONFIGURATION_URI); try { return new URI(uri); } catch (URISyntaxException e) { throw new CacheException("Failed to create the default URI for the javax.cache CoherenceAdapter Implementation", e); } } @Override public Properties getDefaultProperties() { // there are no default properties for this provider return new Properties(); } @Override public CacheManager getCacheManager(URI uri, ClassLoader cl) { return getCacheManager(uri, cl, getDefaultProperties()); } @Override public CacheManager getCacheManager() { return getCacheManager(null, null, null); } @Override public synchronized void close() { WeakHashMap> mapClassLoaderToMgrMap = m_mapClzldrToMgrMap; m_mapClzldrToMgrMap = new WeakHashMap>(); for (Map.Entry> entry : mapClassLoaderToMgrMap.entrySet()) { for (CacheManager mgr : entry.getValue().values()) { mgr.close(); } } m_defaultConfigurationClassName = new AtomicReference(null); } @Override public synchronized void close(ClassLoader cl) { ClassLoader clzldr = (cl == null) ? getDefaultClassLoader() : cl; HashMap mapUriToMgrs = m_mapClzldrToMgrMap.remove(clzldr); if (mapUriToMgrs != null) { for (CacheManager mgr : mapUriToMgrs.values()) { mgr.close(); } } } @Override public synchronized void close(URI u, ClassLoader cl) { URI uri = (u == null) ? getDefaultURI() : u; ClassLoader clzldr = (cl == null) ? getDefaultClassLoader() : cl; HashMap mapUriToMgr = m_mapClzldrToMgrMap.get(clzldr); if (mapUriToMgr != null) { CacheManager mgr = mapUriToMgr.remove(uri); if (mgr != null) { mgr.close(); } if (mapUriToMgr.size() == 0) { m_mapClzldrToMgrMap.remove(clzldr); } } } @Override public boolean isSupported(OptionalFeature feature) { switch (feature) { case STORE_BY_REFERENCE: String defaultConfigurationClassName = getDefaultCoherenceBasedConfigurationClassName(); // The Coherence JCache Adapter implementation has one provider and multiple implementations. // to pass JSR 107 TCK which only uses generic JCache Configuration, // return this value based on what Coherence JCache Adapter implementation is // configured to be used by default. return defaultConfigurationClassName.contains("LocalCacheConfiguration"); default: return false; } } // ----- CoherenceBasedCachingProvider methods -------------------------- /** * Releases the CacheManager with the specified URI and ClassLoader * from this CachingProvider. This does not close the CacheManager. It * simply releases it from being tracked by the CachingProvider. *

* This method does nothing if a CacheManager matching the specified * parameters is not being tracked. * * @param c the ClassLoader of the CacheManager * @param u the URI of the CacheManager */ public synchronized void release(ClassLoader c, URI u) { URI uri = (u == null) ? getDefaultURI() : u; ClassLoader cl = (c == null) ? getDefaultClassLoader() : c; HashMap mapUriToMgr = m_mapClzldrToMgrMap.get(cl); if (mapUriToMgr != null) { mapUriToMgr.remove(uri); if (mapUriToMgr.size() == 0) { m_mapClzldrToMgrMap.remove(cl); } } } /** * Constructs a suitable {@link CacheManager} for the specified parameters. *

* This method may be overridden by sub-classes to provide specialized * {@link CacheManager} implementations. * * @param uri the {@link CacheManager} {@link URI} * @param classLoader the {@link ClassLoader} for the returned {@link CacheManager} * @param properties the custom {@link Properties} for the {@link CacheManager} * * @return a new {@link CacheManager} */ protected CacheManager createCacheMananger(URI uri, ClassLoader classLoader, Properties properties) { // when a URI hasn't been provided, use the default if (uri == null) { uri = getDefaultURI(); } // when properties haven't been provided, use the default if (properties == null) { properties = getDefaultProperties(); } // if a getClassLoader() or Thread.getContextClassLoader() returns null, // then be sure to use method getDefaultClassLoader that guarantees to not return null. if (classLoader == null) { classLoader = getDefaultClassLoader(); } // we need the URI as a String for Coherence String sURI = uri.toString(); // attempt to have the CacheFactoryBuilder load the ConfigurableCacheFactory for the URI ConfigurableCacheFactory ccf; try { if (Logger.isEnabled(Logger.FINER)) { Logger.finer("ConfigurableCacheFactory being configured using configuration file=[" + sURI + "] classloader=" + classLoader); } ccf = CacheFactory.getCacheFactoryBuilder().getConfigurableCacheFactory(sURI, classLoader); Logger.info("getConfigurableCacheFactory returned ccf=" + ccf + " classLoader Hierarchy=" + toStringClassLoaderHierachy(classLoader)); assert(ccf != null); CoherenceBasedCacheManager mgr = new CoherenceBasedCacheManager(this, ccf, uri, classLoader, properties); return mgr; } catch (RuntimeException e) { throw new CacheException("Error processing " + sURI, e); } } /** * Print out ClassLoader hierarchy * * @param ldr ClassLoader to add itself and all parents reachable from it. * * @return result with ClassLoader and its parent(s) classloader hierarchy. */ private static String toStringClassLoaderHierachy(ClassLoader ldr) { StringBuilder bldr = new StringBuilder("Child "); ClassLoader next = ldr; do { bldr.append("ClassLoader[hashcode=").append(next.hashCode() + "] [classloader=" + next + "]"); next = next.getParent(); if (next != null) { bldr.append(" Parent"); } } while (next != null); return bldr.toString(); } /** * Converts a {@link Configuration} into a {@link CoherenceBasedConfiguration} so that we may * create {@link CoherenceBasedCache}s. * * @param cfg the {@link Configuration} to convert * @param classLoader the {@link ClassLoader} to use to locate a suitable {@link CoherenceBasedConfiguration} * (when necessary) * * @param the key type * @param the value type * * @return a {@link CoherenceBasedConfiguration} for use with a {@link CoherenceBasedCacheManager} */ protected CoherenceBasedConfiguration convertConfiguration(Configuration cfg, ClassLoader classLoader) { if (cfg instanceof CoherenceBasedConfiguration) { return (CoherenceBasedConfiguration) cfg; } else if (cfg instanceof CompleteConfiguration) { CompleteConfiguration cfgComplete = (CompleteConfiguration) cfg; String sClassName = getDefaultCoherenceBasedConfigurationClassName(); try { Class clsConfiguration = classLoader.loadClass(sClassName); if (CoherenceBasedConfiguration.class.isAssignableFrom(clsConfiguration)) { Constructor constructor = clsConfiguration.getConstructor(CompleteConfiguration.class); return (CoherenceBasedConfiguration) constructor.newInstance(cfgComplete); } else { throw new ClassCastException("The specified configuration class [" + sClassName + "] does not implement " + CoherenceBasedConfiguration.class.getCanonicalName()); } } catch (ClassNotFoundException e) { throw new UnsupportedOperationException("Failed to load the specified configuration class [" + sClassName + "]", e); } catch (NoSuchMethodException e) { throw new UnsupportedOperationException("The specified configuration class [" + sClassName + "] does not have a public constructor taking a single CompleteConfiguration argument", e); } catch (InstantiationException e) { throw new UnsupportedOperationException("The specified configuration class [" + sClassName + "] could not be instantiated", e); } catch (IllegalAccessException e) { throw new UnsupportedOperationException("The specified configuration class [" + sClassName + "] is not accessible", e); } catch (InvocationTargetException e) { throw new UnsupportedOperationException("The specified configuration class [" + sClassName + "] could not be instantiated", e); } } else { Logger.warn("CoherenceBasedCachingProvider: Ignoring unknown configuration class " + cfg.getClass().getCanonicalName() + " defaulting" + " to basic javax.cache.configuration.MutableConfiguration initialized with base javax.cache.configuration.Configuration " + "values taken from configuration parameter."); // the provided configuration is unknown to this provider so lets instead create a MutableConfiguration MutableConfiguration cfgMutable = new MutableConfiguration(); cfgMutable.setTypes(cfg.getKeyType(), cfg.getValueType()); cfgMutable.setStoreByValue(cfg.isStoreByValue()); // now create a configuration based on our MutableConfiguration return convertConfiguration(cfgMutable, classLoader); } } /** * Determines the fully-qualified-class-name of the default * {@link CoherenceBasedConfiguration} class to use when provided * with a JCache {@link Configuration}. * * @return the fully-qualified-class-name of a {@link CoherenceBasedConfiguration} */ public String getDefaultCoherenceBasedConfigurationClassName() { if (m_defaultConfigurationClassName.get() == null) { // determine the fully-qualified-class-name based on the system-property String sClassName = Config.getProperty(DEFAULT_COHERENCE_JCACHE_CONFIGURATION_CLASS_NAME_SYSTEM_PROPERTY, LocalCacheConfiguration.class.getCanonicalName()); // translate aliases into the fully-qualified-class-name if (sClassName.equalsIgnoreCase("local")) { sClassName = LocalCacheConfiguration.class.getCanonicalName(); } else if (sClassName.equalsIgnoreCase("partitioned")) { sClassName = PartitionedCacheConfiguration.class.getCanonicalName(); } else if (sClassName.equals("passthrough")) { sClassName = PassThroughCacheConfiguration.class.getCanonicalName(); } else if (sClassName.equalsIgnoreCase("extend") || sClassName.equalsIgnoreCase("remote")) { sClassName = RemoteCacheConfiguration.class.getCanonicalName(); } boolean result = m_defaultConfigurationClassName.compareAndSet(null, sClassName); if (result) { Logger.info("Mapping general javax.cache.Configuration implementation to " + "CoherenceBased JCacheConfiguration of " + sClassName); } } return m_defaultConfigurationClassName.get(); } // ----- helpers -------------------------------------------------------- /** * compute if extend client by inspecting value of defaultJCacheConfiguration class value. * * @param defaultJCacheConfigurationClass either system property or getCacheManager property for {@link Constants#DEFAULT_COHERENCE_JCACHE_CONFIGURATION_CLASS_NAME_SYSTEM_PROPERTY} * * @return true iff a RemoteCacheConfiguration would be created based on the above mentioned property. */ private static boolean isExtendClient(String defaultJCacheConfigurationClass) { return defaultJCacheConfigurationClass != null && (defaultJCacheConfigurationClass.equalsIgnoreCase("remote") || defaultJCacheConfigurationClass.equalsIgnoreCase("extend") || defaultJCacheConfigurationClass .equalsIgnoreCase("com.tangosol.coherence.jcache.remotecache.RemoteConfiguration")); } // ----- data members --------------------------------------------------- /** * The CacheManagers scoped by ClassLoader and URI. */ private WeakHashMap> m_mapClzldrToMgrMap; /** * Map {@link MutableConfiguration} and all non Coherence based {@link Configuration} to this default Coherence Based Cache Configuration. * * Potential values include fully qualified cannonical name of {@link LocalCacheConfiguration} and {@link PartitionedCacheConfiguration}. */ private AtomicReference m_defaultConfigurationClassName = new AtomicReference(null); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy