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

com.hazelcast.cache.impl.AbstractHazelcastCacheManager Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.
 *
 * 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 com.hazelcast.cache.impl;

import com.hazelcast.cache.CacheUtil;
import com.hazelcast.cache.HazelcastCacheManager;
import com.hazelcast.cache.ICache;
import com.hazelcast.config.CacheConfig;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceNotActiveException;
import com.hazelcast.core.LifecycleEvent;
import com.hazelcast.core.LifecycleListener;
import com.hazelcast.core.LifecycleService;
import com.hazelcast.util.EmptyStatement;

import javax.cache.CacheException;
import javax.cache.CacheManager;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.configuration.CompleteConfiguration;
import javax.cache.configuration.Configuration;
import javax.cache.spi.CachingProvider;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.hazelcast.util.Preconditions.checkNotNull;

/**
 * 

* Abstract {@link HazelcastCacheManager} (also {@link CacheManager} as indirect) implementation * provides shared functionality to server and client cache managers. * There are two cache managers which can be accessed via their providers. *

    *
  • Client: HazelcastClientCacheManager.
  • *
  • Server: HazelcastServerCacheManager.
  • *
*

*

* {@link AbstractHazelcastCacheManager} manages the lifecycle of the caches created or accessed through itself. *

* @see HazelcastCacheManager * @see CacheManager */ public abstract class AbstractHazelcastCacheManager implements HazelcastCacheManager { protected final ConcurrentMap> caches = new ConcurrentHashMap>(); protected final URI uri; protected final WeakReference classLoaderReference; protected final Properties properties; protected final String cacheNamePrefix; protected final boolean isDefaultURI; protected final boolean isDefaultClassLoader; protected final CachingProvider cachingProvider; protected final HazelcastInstance hazelcastInstance; private final AtomicBoolean isClosed = new AtomicBoolean(false); private final AtomicBoolean isDestroyed = new AtomicBoolean(false); private final String lifecycleListenerRegistrationId; public AbstractHazelcastCacheManager(CachingProvider cachingProvider, HazelcastInstance hazelcastInstance, URI uri, ClassLoader classLoader, Properties properties) { checkNotNull(cachingProvider, "CachingProvider missing"); this.cachingProvider = cachingProvider; checkNotNull(hazelcastInstance, "hazelcastInstance cannot be null"); this.hazelcastInstance = hazelcastInstance; this.isDefaultURI = uri == null || cachingProvider.getDefaultURI().equals(uri); this.uri = isDefaultURI ? cachingProvider.getDefaultURI() : uri; this.isDefaultClassLoader = classLoader == null || cachingProvider.getDefaultClassLoader().equals(classLoader); ClassLoader localClassLoader = isDefaultClassLoader ? cachingProvider.getDefaultClassLoader() : classLoader; this.classLoaderReference = new WeakReference(localClassLoader); this.properties = properties == null ? new Properties() : new Properties(properties); this.cacheNamePrefix = cacheNamePrefix(); this.lifecycleListenerRegistrationId = registerLifecycleListener(); } private > ICacheInternal createCacheInternal(String cacheName, C configuration) throws IllegalArgumentException { checkIfManagerNotClosed(); checkNotNull(cacheName, "cacheName must not be null"); checkNotNull(configuration, "configuration must not be null"); CacheConfig newCacheConfig = createCacheConfig(cacheName, configuration); if (caches.containsKey(newCacheConfig.getNameWithPrefix())) { throw new CacheException("A cache named " + cacheName + " already exists."); } // Create cache config on all nodes as sync CacheConfig currentCacheConfig = createCacheConfig(cacheName, newCacheConfig, true, true); // Create cache proxy object with cache config ICacheInternal cacheProxy = createCacheProxy(newCacheConfig); if (currentCacheConfig == null) { // Put created cache config. // Single thread region because "createConfigOnPartition" is single threaded by partition thread addCacheConfigIfAbsent(newCacheConfig); // Put created cache. No need to a "putIfAbsent" as this is a single threaded region caches.put(newCacheConfig.getNameWithPrefix(), cacheProxy); // Register listeners registerListeners(newCacheConfig, cacheProxy); return cacheProxy; } ICacheInternal cache = getOrPutIfAbsent(currentCacheConfig.getNameWithPrefix(), cacheProxy); CacheConfig config = cache.getConfiguration(CacheConfig.class); if (config.equals(newCacheConfig)) { return (ICacheInternal) cache; } throw new CacheException("A cache named " + cacheName + " already exists."); } @Override public HazelcastInstance getHazelcastInstance() { return hazelcastInstance; } @Override public > ICache createCache(String cacheName, C configuration) throws IllegalArgumentException { return createCacheInternal(cacheName, configuration); } private ICacheInternal getOrPutIfAbsent(String nameWithPrefix, ICacheInternal cacheProxy) { ICacheInternal cache = caches.get(nameWithPrefix); if (cache == null) { ICacheInternal iCache = caches.putIfAbsent(nameWithPrefix, cacheProxy); cache = iCache != null ? iCache : cacheProxy; } return cache; } @Override public CachingProvider getCachingProvider() { return cachingProvider; } @Override public URI getURI() { return this.uri; } @Override public ClassLoader getClassLoader() { return classLoaderReference.get(); } @Override public Properties getProperties() { return properties; } @Override public ICache getCache(String cacheName, Class keyType, Class valueType) { checkIfManagerNotClosed(); checkNotNull(keyType, "keyType can not be null"); checkNotNull(valueType, "valueType can not be null"); ICacheInternal cache = getCacheUnchecked(cacheName); if (cache != null) { Configuration configuration = cache.getConfiguration(CacheConfig.class); if (configuration.getKeyType() != null && configuration.getKeyType().equals(keyType)) { if (configuration.getValueType() != null && configuration.getValueType().equals(valueType)) { return ensureOpenIfAvailable((ICacheInternal) cache); } else { throw new ClassCastException( "Incompatible cache value types specified, expected " + configuration.getValueType() + " but " + valueType + " was specified"); } } else { throw new ClassCastException( "Incompatible cache key types specified, expected " + configuration.getKeyType() + " but " + keyType + " was specified"); } } return null; } public ICache getOrCreateCache(String cacheName, CacheConfig cacheConfig) { checkIfManagerNotClosed(); String cacheNameWithPrefix = getCacheNameWithPrefix(cacheName); ICacheInternal cache = caches.get(cacheNameWithPrefix); if (cache == null) { cache = createCacheInternal(cacheName, cacheConfig); } return ensureOpenIfAvailable((ICacheInternal) cache); } @Override public ICache getCache(String cacheName) { checkIfManagerNotClosed(); ICacheInternal cache = getCacheUnchecked(cacheName); if (cache != null) { Configuration configuration = cache.getConfiguration(CacheConfig.class); if (Object.class.equals(configuration.getKeyType()) && Object.class.equals(configuration.getValueType())) { return ensureOpenIfAvailable((ICacheInternal) cache); } else { throw new IllegalArgumentException( "Cache " + cacheName + " was " + "defined with specific types Cache<" + configuration.getKeyType() + ", " + configuration.getValueType() + "> " + "in which case CacheManager.getCache(String, Class, Class) must be used"); } } return null; } protected ICacheInternal ensureOpenIfAvailable(ICacheInternal cache) { if (cache != null && cache.isClosed() && !cache.isDestroyed()) { cache.open(); } return cache; } protected ICacheInternal getCacheUnchecked(String cacheName) { String cacheNameWithPrefix = getCacheNameWithPrefix(cacheName); ICacheInternal cache = caches.get(cacheNameWithPrefix); if (cache == null) { CacheConfig cacheConfig = findCacheConfig(cacheNameWithPrefix, cacheName, true, true); if (cacheConfig == null) { // No cache found return null; } // Create the cache proxy which already exists in the cluster as config ICacheInternal cacheProxy = createCacheProxy(cacheConfig); // Put created cache config. addCacheConfigIfAbsent(cacheConfig); cache = caches.putIfAbsent(cacheNameWithPrefix, cacheProxy); if (cache == null) { registerListeners(cacheConfig, cacheProxy); cache = cacheProxy; } } return cache; } @Override public Iterable getCacheNames() { Set names; if (isClosed()) { names = Collections.emptySet(); } else { names = new LinkedHashSet(); for (Map.Entry> entry : caches.entrySet()) { String nameWithPrefix = entry.getKey(); int index = nameWithPrefix.indexOf(cacheNamePrefix) + cacheNamePrefix.length(); final String name = nameWithPrefix.substring(index); names.add(name); } } return Collections.unmodifiableCollection(names); } @Override public void destroyCache(String cacheName) { removeCache(cacheName, true); } @Override public void removeCache(String cacheName, boolean destroy) { checkIfManagerNotClosed(); checkNotNull(cacheName, "cacheName cannot be null"); String cacheNameWithPrefix = getCacheNameWithPrefix(cacheName); ICacheInternal cache = caches.remove(cacheNameWithPrefix); if (cache != null && destroy) { cache.destroy(); } removeCacheConfigFromLocal(cacheNameWithPrefix); } /** * Removes the local copy of the cache configuration if one exists. * Default implementation does not require it. But client implementation overrides this to track a local copy * of the config. * * @param cacheName cache name. */ protected void removeCacheConfigFromLocal(String cacheName) { } private String registerLifecycleListener() { return hazelcastInstance.getLifecycleService().addLifecycleListener(new LifecycleListener() { @Override public void stateChanged(LifecycleEvent event) { if (event.getState() == LifecycleEvent.LifecycleState.SHUTTING_DOWN) { onShuttingDown(); } } }); } private void deregisterLifecycleListener() { LifecycleService lifecycleService = hazelcastInstance.getLifecycleService(); try { lifecycleService.removeLifecycleListener(lifecycleListenerRegistrationId); } catch (HazelcastInstanceNotActiveException e) { // if hazelcastInstance is terminated already, // `lifecycleService.removeLifecycleListener` will throw HazelcastInstanceNotActiveException. // We can safely ignore this exception. See TerminatedLifecycleService. EmptyStatement.ignore(e); } } @Override public void close() { if (isDestroyed.get() || !isClosed.compareAndSet(false, true)) { return; } deregisterLifecycleListener(); for (ICacheInternal cache : caches.values()) { cache.close(); } postClose(); // TODO do we need to clear it as "caches.clear();" } /** * Destroy all managed caches. */ @Override public void destroy() { if (!isDestroyed.compareAndSet(false, true)) { return; } deregisterLifecycleListener(); for (ICacheInternal cache : caches.values()) { cache.destroy(); } caches.clear(); isClosed.set(true); postDestroy(); } protected void postDestroy() { } @Override public boolean isClosed() { return isClosed.get() || !hazelcastInstance.getLifecycleService().isRunning(); } protected void checkIfManagerNotClosed() { if (isClosed()) { throw new IllegalStateException(); } } /** * This method calculates a fixed string based on the URI and classloader using the formula: *

/hz[/uri][/classloader]/

*

URI and classloader are dropped if they have default values.

* * @return the calculated cache prefix. */ protected String cacheNamePrefix() { String cacheNamePrefix = CacheUtil.getPrefix( isDefaultURI ? null : uri, isDefaultClassLoader ? null : getClassLoader()); if (cacheNamePrefix == null) { return HazelcastCacheManager.CACHE_MANAGER_PREFIX; } else { return HazelcastCacheManager.CACHE_MANAGER_PREFIX + cacheNamePrefix; } } @Override public String getCacheNameWithPrefix(String name) { return cacheNamePrefix + name; } protected > CacheConfig createCacheConfig(String cacheName, C configuration) { CacheConfig cacheConfig; if (configuration instanceof CompleteConfiguration) { cacheConfig = new CacheConfig((CompleteConfiguration) configuration); } else { cacheConfig = new CacheConfig(); cacheConfig.setStoreByValue(configuration.isStoreByValue()); final Class keyType = configuration.getKeyType(); final Class valueType = configuration.getValueType(); cacheConfig.setTypes(keyType, valueType); } cacheConfig.setName(cacheName); cacheConfig.setManagerPrefix(this.cacheNamePrefix); cacheConfig.setUriString(getURI().toString()); return cacheConfig; } protected void registerListeners(CacheConfig cacheConfig, ICache source) { Iterator> iterator = cacheConfig.getCacheEntryListenerConfigurations().iterator(); while (iterator.hasNext()) { CacheEntryListenerConfiguration listenerConfig = iterator.next(); ((ICacheInternal) source).registerCacheEntryListener(listenerConfig, false); } } @Override public String toString() { return "HazelcastCacheManager{hazelcastInstance=" + hazelcastInstance + ", cachingProvider=" + cachingProvider + '}'; } protected abstract void addCacheConfigIfAbsent(CacheConfig cacheConfig); protected abstract ICacheInternal createCacheProxy(CacheConfig cacheConfig); protected abstract CacheConfig findCacheConfig(String cacheName, String simpleCacheName, boolean createAlsoOnOthers, boolean syncCreate); protected abstract CacheConfig createCacheConfig(String cacheName, CacheConfig config, boolean createAlsoOnOthers, boolean syncCreate); protected abstract CacheConfig getCacheConfig(String cacheName, String simpleCacheName); protected abstract void postClose(); protected abstract void onShuttingDown(); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy