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

javax.cache.Caching Maven / Gradle / Ivy

There is a newer version: 1.1.1
Show newest version
/**
 * Copyright 2011-2016 Terracotta, Inc.
 * Copyright 2011-2016 Oracle America Incorporated
 *
 * Licensed 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 javax.cache;

import javax.cache.spi.CachingProvider;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.ServiceLoader;
import java.util.WeakHashMap;

/**
 * The {@link Caching} class provides a convenient means for an application to
 * acquire an appropriate {@link CachingProvider} implementation.
 * 

* While defined as part of the specification, its use is not required. * Applications and/or containers may instead choose to directly instantiate a * {@link CachingProvider} implementation based on implementation specific * instructions. *

* When using the {@link Caching} class, {@link CachingProvider} implementations * are automatically discovered when they follow the conventions outlined by the * Java Development Kit {@link ServiceLoader} class. *

* Although automatically discovered, applications that choose to use this class * should not make assumptions regarding the order in which implementations are * returned by the {@link #getCachingProviders()} or * {@link #getCachingProviders(ClassLoader)} methods. *

* For a {@link CachingProvider} to be automatically discoverable by the * {@link Caching} class, the fully qualified class name of the * {@link CachingProvider} implementation must be declared in the following * file: *

 *   META-INF/services/javax.cache.spi.CachingProvider
 * 
* This file must be resolvable via the class path. *

* For example, in the reference implementation the contents of this file are: * org.jsr107.ri.RICachingProvider *

* Alternatively when the fully qualified class name of a * {@link CachingProvider} implementation is specified using the system property * javax.cache.spi.cachingprovider, that implementation will be used * as the default {@link CachingProvider}. *

* All {@link CachingProvider}s that are automatically detected or explicitly * declared and loaded by the {@link Caching} class are maintained in an * internal registry. Consequently when a previously loaded * {@link CachingProvider} is requested, it will be simply returned from the * internal registry, without reloading and/or instantiating the said * implementation again. *

* As required by some applications and containers, multiple co-existing * {@link CachingProvider}s implementations, from the same or different * implementors are permitted at runtime. *

* To iterate through those that are currently registered a developer may use * the following methods: *

    *
  1. {@link #getCachingProviders()}
  2. *
  3. {@link #getCachingProviders(ClassLoader)}
  4. *
* To request a specific {@link CachingProvider} implementation, a developer * should use either the {@link #getCachingProvider(String)} or * {@link #getCachingProvider(String, ClassLoader)} method. *

* Where multiple {@link CachingProvider}s are present, the * {@link CachingProvider} returned by getters {@link #getCachingProvider()} and * {@link #getCachingProvider(ClassLoader)} is undefined and as a result a * {@link CacheException} will be thrown when attempted. * * @author Brian Oliver * @author Greg Luck * @author Yannis Cosmadopoulos * @since 1.0 * @see ServiceLoader * @see CachingProvider */ public final class Caching { /** * The javax.cache.spi.cachingprovider constant. */ public static final String JAVAX_CACHE_CACHING_PROVIDER = "javax.cache" + ".spi.CachingProvider"; /** * The {@link CachingProviderRegistry} that tracks the {@link CachingProvider}s. */ private static final CachingProviderRegistry CACHING_PROVIDERS = new CachingProviderRegistry(); /** * No public constructor as all methods are static. */ private Caching() { } /** * Obtains the {@link ClassLoader} to use for API methods that don't * explicitly require a {@link ClassLoader} but internally require one. *

* By default this is the {@link Thread#getContextClassLoader()}. * * @return the default {@link ClassLoader} */ public static ClassLoader getDefaultClassLoader() { return CACHING_PROVIDERS.getDefaultClassLoader(); } /** * Set the {@link ClassLoader} to use for API methods that don't explicitly * require a {@link ClassLoader}, but internally use one. * * @param classLoader the {@link ClassLoader} or null if the * calling {@link Thread#getContextClassLoader()} should * be used */ public static void setDefaultClassLoader(ClassLoader classLoader) { CACHING_PROVIDERS.setDefaultClassLoader(classLoader); } /** * Obtains the default {@link CachingProvider} available via the * {@link #getDefaultClassLoader()}. * * @return the {@link CachingProvider} * @throws CacheException should zero, or more than one * {@link CachingProvider} be available on the * classpath, or it could not be loaded * @throws SecurityException when the operation could not be performed * due to the current security settings */ public static CachingProvider getCachingProvider() { return CACHING_PROVIDERS.getCachingProvider(); } /** * Obtains the single {@link CachingProvider} visible to the specified * {@link ClassLoader}. * * @param classLoader the {@link ClassLoader} to use for loading the * {@link CachingProvider} * @return the {@link CachingProvider} * @throws CacheException should zero, or more than one * {@link CachingProvider} be available on the * classpath, or it could not be loaded * @throws SecurityException when the operation could not be performed * due to the current security settings * @see #getCachingProviders(ClassLoader) */ public static CachingProvider getCachingProvider(ClassLoader classLoader) { return CACHING_PROVIDERS.getCachingProvider(classLoader); } /** * Obtains the {@link CachingProvider}s that are available via the * {@link #getDefaultClassLoader()}. *

* If a javax.cache.spi.cachingprovider system property is defined, * only that {@link CachingProvider} specified by that property is returned. * Otherwise all {@link CachingProvider}s that are available via a * {@link ServiceLoader} for {@link CachingProvider}s using the default * {@link ClassLoader} (including those previously requested via * {@link #getCachingProvider(String)}) are returned. * * @return an {@link Iterable} of {@link CachingProvider}s loaded by the * specified {@link ClassLoader} */ public static Iterable getCachingProviders() { return CACHING_PROVIDERS.getCachingProviders(); } /** * Obtains the {@link CachingProvider}s that are available via the specified * {@link ClassLoader}. *

* If a javax.cache.spi.cachingprovider system property is defined, * only that {@link CachingProvider} specified by that property is returned. * Otherwise all {@link CachingProvider}s that are available via a * {@link ServiceLoader} for {@link CachingProvider}s using the specified * {@link ClassLoader} (including those previously requested via * {@link #getCachingProvider(String, ClassLoader)}) are returned. * * @param classLoader the {@link ClassLoader} of the returned * {@link CachingProvider}s * @return an {@link Iterable} of {@link CachingProvider}s loaded by the * specified {@link ClassLoader} */ public static Iterable getCachingProviders( ClassLoader classLoader) { return CACHING_PROVIDERS.getCachingProviders(classLoader); } /** * Obtain the {@link CachingProvider} that is implemented by the specified * fully qualified class name using the {@link #getDefaultClassLoader()}. * Should this {@link CachingProvider} already be loaded it is simply returned, * otherwise an attempt will be made to load and instantiate the specified * class (using a no-args constructor). * * @param fullyQualifiedClassName the fully qualified class name of the * {@link CachingProvider} * @return the {@link CachingProvider} * @throws CacheException if the {@link CachingProvider} cannot be created * @throws SecurityException when the operation could not be performed * due to the current security settings */ public static CachingProvider getCachingProvider(String fullyQualifiedClassName) { return CACHING_PROVIDERS.getCachingProvider(fullyQualifiedClassName); } /** * Obtain the {@link CachingProvider} that is implemented by the specified * fully qualified class name using the provided {@link ClassLoader}. * Should this {@link CachingProvider} already be loaded it is returned, * otherwise an attempt will be made to load and instantiate the specified * class (using a no-args constructor). * * @param fullyQualifiedClassName the fully qualified class name of the * {@link CachingProvider} * @param classLoader the {@link ClassLoader} to load the * {@link CachingProvider} * @return the {@link CachingProvider} * @throws CacheException if the {@link CachingProvider} cannot be created * @throws SecurityException when the operation could not be performed * due to the current security settings */ public static CachingProvider getCachingProvider(String fullyQualifiedClassName, ClassLoader classLoader) { return CACHING_PROVIDERS.getCachingProvider(fullyQualifiedClassName, classLoader); } /** * A convenience that method that looks up a managed {@link Cache} given its * name. using the default CachingProvider and CacheManager * . For the full range of Cache look up methods see * {@link CacheManager}. *

* This method must be used for {@link Cache}s that were configured with * runtime key and value types. Use {@link CacheManager#getCache(String)} for * {@link Cache}s where these were not specified. *

* Implementations must ensure that the key and value types are the same as * those configured for the {@link Cache} prior to returning from this method. *

* Implementations may further perform type checking on mutative cache operations * and throw a {@link ClassCastException} if these checks fail. *

* Implementations that support declarative mechanisms for pre-configuring * {@link Cache}s may return a pre-configured {@link Cache} instead of * null. * @param the type of key * @param the type of value * @param cacheName the name of the managed {@link Cache} to acquire * @param keyType the expected {@link Class} of the key * @param valueType the expected {@link Class} of the value * @return the Cache or null if it does exist or can't be pre-configured * @throws IllegalStateException if the CacheManager is * {@link CacheManager#isClosed()} * @throws IllegalArgumentException if the specified key and/or value types are * incompatible with the configured cache. * @throws SecurityException when the operation could not be performed * due to the current security settings * @see CacheManager#getCache(String, Class, Class) * @see CacheManager#getCache(String) */ public static Cache getCache(String cacheName, Class keyType, Class valueType) { return getCachingProvider().getCacheManager().getCache(cacheName, keyType, valueType); } /** * Maintains a registry of loaded {@link CachingProvider}s scoped by * {@link ClassLoader}. */ private static class CachingProviderRegistry { /** * The {@link CachingProvider}s by Class Name organized by the * {@link ClassLoader} was used to load them. */ private WeakHashMap> cachingProviders; /** * The default {@link ClassLoader}. When null the * {@link Thread#getContextClassLoader()} will be used. */ private volatile ClassLoader classLoader; /** * Constructs a CachingProviderManager. */ public CachingProviderRegistry() { this.cachingProviders = new WeakHashMap>(); this.classLoader = null; } /** * Obtains the {@link ClassLoader} to use for API methods that don't * explicitly require a {@link ClassLoader} but internally require one. *

* By default this is the {@link Thread#getContextClassLoader()}. *

* @return the default {@link ClassLoader} */ public ClassLoader getDefaultClassLoader() { ClassLoader loader = classLoader; return loader == null ? Thread.currentThread().getContextClassLoader() : loader; } /** * Set the {@link ClassLoader} to use for API methods that don't explicitly * require a {@link ClassLoader}, but internally use one. * * @param classLoader the {@link ClassLoader} or null if the * calling {@link Thread#getContextClassLoader()} should * be used */ public void setDefaultClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } /** * Obtains the only {@link CachingProvider} defined by the * {@link #getDefaultClassLoader()}. *

* Should zero or more than one {@link CachingProvider}s be available, a * CacheException is thrown. *

* @return the {@link CachingProvider} * @throws CacheException should zero or more than one * {@link CachingProvider} be available * or a {@link CachingProvider} could not be loaded * @see #getCachingProvider(ClassLoader) * @see #getCachingProviders(ClassLoader) */ public CachingProvider getCachingProvider() { return getCachingProvider(getDefaultClassLoader()); } /** * Obtains the only {@link CachingProvider} defined by the specified * {@link ClassLoader}. *

* Should zero or more than one {@link CachingProvider}s be available, a * CacheException is thrown. *

* @param classLoader the {@link ClassLoader} to use for loading the * {@link CachingProvider} * @return the {@link CachingProvider} * @throws CacheException should zero or more than one * {@link CachingProvider} be available * or a {@link CachingProvider} could not be loaded * @see #getCachingProviders(ClassLoader) */ public CachingProvider getCachingProvider(ClassLoader classLoader) { Iterator iterator = getCachingProviders(classLoader).iterator(); if (iterator.hasNext()) { CachingProvider provider = iterator.next(); if (iterator.hasNext()) { throw new CacheException("Multiple CachingProviders have been configured when only a single CachingProvider is expected"); } else { return provider; } } else { throw new CacheException("No CachingProviders have been configured"); } } /** * Obtain the {@link CachingProvider}s that are available via the * {@link #getDefaultClassLoader()}. *

* If a javax.cache.spi.cachingprovider system property is defined, * only that {@link CachingProvider} specified by that property is returned. * Otherwise all {@link CachingProvider}s that are available via a * {@link ServiceLoader} for {@link CachingProvider}s using the default * {@link ClassLoader} (and those explicitly requested via * {@link #getCachingProvider(String)}) are returned. *

* @return an {@link Iterable} of {@link CachingProvider}s loaded by the * default {@link ClassLoader} */ public Iterable getCachingProviders() { return getCachingProviders(getDefaultClassLoader()); } /** * Obtain the {@link CachingProvider}s that are available via the specified * {@link ClassLoader}. *

* If a javax.cache.spi.cachingprovider system property is defined, * only that {@link CachingProvider} specified by that property is returned. * Otherwise all {@link CachingProvider}s that are available via a * {@link ServiceLoader} for {@link CachingProvider}s using the specified * {@link ClassLoader} (and those explicitly requested via * {@link #getCachingProvider(String, ClassLoader)}) are returned. *

* @param classLoader the {@link ClassLoader} of the returned * {@link CachingProvider}s * @return an {@link Iterable} of {@link CachingProvider}s loaded by the * specified {@link ClassLoader} */ public synchronized Iterable getCachingProviders(ClassLoader classLoader) { final ClassLoader serviceClassLoader = classLoader == null ? getDefaultClassLoader() : classLoader; LinkedHashMap providers = cachingProviders.get(serviceClassLoader); if (providers == null) { if (System.getProperties().containsKey(JAVAX_CACHE_CACHING_PROVIDER)) { String className = System.getProperty(JAVAX_CACHE_CACHING_PROVIDER); providers = new LinkedHashMap(); providers.put(className, loadCachingProvider(className, serviceClassLoader)); } else { providers = AccessController.doPrivileged(new PrivilegedAction>() { @Override public LinkedHashMap run() { LinkedHashMap result = new LinkedHashMap(); ServiceLoader serviceLoader = ServiceLoader.load(CachingProvider.class, serviceClassLoader); for (CachingProvider provider : serviceLoader) { result.put(provider.getClass().getName(), provider); } return result; } }); } cachingProviders.put(serviceClassLoader, providers); } return providers.values(); } /** * Obtain the {@link CachingProvider} that is implemented by the specified * fully qualified class name using the {@link #getDefaultClassLoader()}. * Should this {@link CachingProvider} already be loaded it is simply * returned, otherwise an attempt will be made to load and instantiate the * specified class name (using a no-args constructor). * * @param fullyQualifiedClassName the fully qualified class name of the * {@link CachingProvider} * @return the {@link CachingProvider} * @throws CacheException when the {@link CachingProvider} can't be created */ public CachingProvider getCachingProvider(String fullyQualifiedClassName) { return getCachingProvider(fullyQualifiedClassName, getDefaultClassLoader()); } /** * Load and instantiate the {@link CachingProvider} with the specified * fully qualified class name using the provided {@link ClassLoader} * * @param fullyQualifiedClassName the name of the {@link CachingProvider} * class * @param classLoader the {@link ClassLoader} to use * @return a new {@link CachingProvider} instance * @throws CacheException if the specified {@link CachingProvider} could not be * loaded * or the specified class is not a {@link * CachingProvider} */ protected CachingProvider loadCachingProvider(String fullyQualifiedClassName, ClassLoader classLoader) throws CacheException { synchronized (classLoader) { try { Class clazz = classLoader.loadClass(fullyQualifiedClassName); if (CachingProvider.class.isAssignableFrom(clazz)) { return ((Class) clazz).newInstance(); } else { throw new CacheException("The specified class [" + fullyQualifiedClassName + "] is not a CachingProvider"); } } catch (Exception e) { throw new CacheException("Failed to load the CachingProvider [" + fullyQualifiedClassName + "]", e); } } } /** * Obtain the {@link CachingProvider} that is implemented by the specified * fully qualified class name using the provided {@link ClassLoader}. * Should this {@link CachingProvider} already be loaded it is returned, * otherwise an attempt will be made to load and instantiate the specified * class (using a no-args constructor). * * @param fullyQualifiedClassName the fully qualified class name of the * {@link CachingProvider} * @param classLoader the {@link ClassLoader} to load the * {@link CachingProvider} * @return the {@link CachingProvider} * @throws CacheException when the {@link CachingProvider} can't be created */ public synchronized CachingProvider getCachingProvider(String fullyQualifiedClassName, ClassLoader classLoader) { ClassLoader serviceClassLoader = classLoader == null ? getDefaultClassLoader() : classLoader; LinkedHashMap providers = cachingProviders.get(serviceClassLoader); if (providers == null) { // first load the CachingProviders for the {@link ClassLoader} // this may automatically load the CachingProvider we desire getCachingProviders(serviceClassLoader); providers = cachingProviders.get(serviceClassLoader); } CachingProvider provider = providers.get(fullyQualifiedClassName); if (provider == null) { provider = loadCachingProvider(fullyQualifiedClassName, serviceClassLoader); providers.put(fullyQualifiedClassName, provider); } return provider; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy