package org.ff4j.cache;
/*
* #%L
* ff4j-store-jcache
* %%
* Copyright (C) 2013 - 2015 FF4J
* %%
* 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.
* #L%
*/
import java.util.HashSet;
import java.util.Set;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.spi.CachingProvider;
import org.ff4j.core.Feature;
import org.ff4j.property.Property;
/**
* Implementation of {@link FF4JCacheManager} with reference interface JCache {@link Cache}.
*
* @author Cedrick Lunven (@clunven)</a>
*/
public class FF4jJCacheManager implements FF4JCacheManager {
/** cache name of the features. */
protected static final String CACHENAME_FEATURES = "ff4jFeatures";
/** cache name of the properties. */
protected static final String CACHENAME_PROPERTIES = "ff4jProperties";
/** JCache associated CachingProvider in order to create 'CacheManager'. */
private CachingProvider cachingProvider;
/** JCache associated cache manager. */
private CacheManager cacheManager;
/** Implementing a JCache CacheProvider. */
protected Cache<String, Feature> featuresCache;
/** Implementing a JCache CacheProvider. */
@SuppressWarnings("rawtypes")
protected Cache<String, Property> propertiesCache;
/**
* Initialisation of internal caches.
*/
public FF4jJCacheManager() {
}
/**
* Constructory avec provider.
*
* @param provider
*/
public FF4jJCacheManager(CachingProvider provider) {
this.cachingProvider = provider;
initCaches();
}
/**
* Initialisation of internal caches.
*/
public FF4jJCacheManager(String providerClassName) {
this.cachingProvider = initCachingProvider(providerClassName);
initCaches();
}
private void initCaches() {
// invoke the jCache 'getCacheManager()' to init cache Manager
this.cacheManager = getCachingProvider().getCacheManager();
featuresCache = createCacheForFeatures();
propertiesCache = createCacheForProperties();
}
/**
* Default initialisation of cache.
*
* @return
*/
protected Cache<String, Feature> createCacheForFeatures() {
if (null == getCacheManager().getCache(CACHENAME_FEATURES, String.class, Feature.class)) {
getCacheManager().createCache(CACHENAME_FEATURES, getFeatureCacheConfiguration());
}
return getCacheManager().getCache(CACHENAME_FEATURES, String.class, Feature.class);
}
/**
* Default initialisation of cache.
*
* @return
*/
@SuppressWarnings("rawtypes")
protected Cache<String, Property> createCacheForProperties() {
if (null == getCacheManager().getCache(CACHENAME_PROPERTIES, String.class, Property.class)) {
getCacheManager().createCache(CACHENAME_PROPERTIES, getPropertyCacheConfiguration());
}
return getCacheManager().getCache(CACHENAME_PROPERTIES, String.class, Property.class);
}
/** {@inheritDoc} */
public Set<String> listCachedFeatureNames() {
Set<String> keys = new HashSet<>();
// Implements iterate, more elegant as stream how ?
getFeaturesCache().forEach(e->keys.add(e.getKey()));
return keys;
}
/** {@inheritDoc} */
public Object getNativeCache() {
if (featuresCache == null) {
throw new IllegalArgumentException("Cannot ");
}
return featuresCache;
}
/** {@inheritDoc} */
public String getCacheProviderName() {
return "jCache:" + featuresCache.getName() +
":" + featuresCache.getCacheManager().getCachingProvider().toString();
}
/** {@inheritDoc} */
@Override
public void clearFeatures() {
getFeaturesCache().clear();
}
/** {@inheritDoc} */
@Override
public void clearProperties() {
getPropertiesCache().clear();
}
/** {@inheritDoc} */
@Override
public void evictFeature(String featureId) {
if (getFeaturesCache().containsKey(featureId)) {
getFeaturesCache().remove(featureId);
}
}
/** {@inheritDoc} */
@Override
public void evictProperty(String propertyName) {
if (getPropertiesCache().containsKey(propertyName)) {
getPropertiesCache().remove(propertyName);
}
}
/** {@inheritDoc} */
@Override
public void putFeature(Feature feat) {
getFeaturesCache().put(feat.getUid(), feat);
}
/** {@inheritDoc} */
@Override
public void putProperty(Property<?> feat) {
getPropertiesCache().put(feat.getName(), feat);
}
/** {@inheritDoc} */
@Override
public Feature getFeature(String featureId) {
return getFeaturesCache().get(featureId);
}
/** {@inheritDoc} */
@Override
public Property<?> getProperty(String name) {
return getPropertiesCache().get(name);
}
/** {@inheritDoc} */
@Override
public Set<String> listCachedPropertyNames() {
Set<String> keys = new HashSet<>();
// Implements iterate, more elegant as stream how ?
getPropertiesCache().forEach(e->keys.add(e.getKey()));
return keys;
}
/** {@inheritDoc} */
@Override
public Object getFeatureNativeCache() {
return getFeaturesCache();
}
/** {@inheritDoc} */
@Override
public Object getPropertyNativeCache() {
return getPropertiesCache();
}
/**
* Getter accessor for attribute 'featuresCache'.
*
* @return
* current value of 'featuresCache'
*/
public Cache<String, Feature> getFeaturesCache() {
if (featuresCache == null) {
initCaches();
}
return featuresCache;
}
/**
* Setter accessor for attribute 'featuresCache'.
* @param featuresCache
* new value for 'featuresCache '
*/
public void setFeaturesCache(Cache<String, Feature> featuresCache) {
this.featuresCache = featuresCache;
}
/**
* Getter accessor for attribute 'propertiesCache'.
*
* @return
* current value of 'propertiesCache'
*/
@SuppressWarnings("rawtypes")
public Cache<String, Property> getPropertiesCache() {
if (propertiesCache == null) {
initCaches();
}
return propertiesCache;
}
/**
* Initialize cache configuration, could be overriden.
*
* @return
* cache default configuration
*/
protected MutableConfiguration< String, Feature> getFeatureCacheConfiguration() {
MutableConfiguration<String, Feature> featuresCacheConfig = new MutableConfiguration<>();
featuresCacheConfig.setTypes(String.class, Feature.class);
featuresCacheConfig.setStoreByValue(true);
featuresCacheConfig.setStatisticsEnabled(false);
return featuresCacheConfig;
}
/**
* Initialize cache configuration, could be overriden.
*
* @return
* cache default configuration
*/
@SuppressWarnings("rawtypes")
protected MutableConfiguration< String, Property> getPropertyCacheConfiguration() {
MutableConfiguration<String, Property> propertiesCacheConfig = new MutableConfiguration<>();
propertiesCacheConfig.setTypes(String.class, Property.class);
propertiesCacheConfig.setStoreByValue(true);
propertiesCacheConfig.setStatisticsEnabled(false);
return propertiesCacheConfig;
}
/**
* Default Initialisation of {@link CachingProvider}. It will work only is there is
* a single {@link CachingProvider} implementation within classpath. Otherwise should must
* overriden it to initialize with your own.
*
* @return
* specialization of {@link CachingProvider} (JCache)
*/
protected CachingProvider initCachingProvider(String cachingProviderClassname) {
try {
if (cachingProviderClassname == null) {
return Caching.getCachingProvider();
}
return Caching.getCachingProvider(cachingProviderClassname);
} catch(RuntimeException re) {
/*
* Some cache implementation do not provide CachingProvider but the cacheManager
* work properly. As a consequence, caching provider can be null and should not throw
* caching exception.
*/
return null;
}
}
/**
* Getter accessor for attribute 'cachingProvider'.
*
* @return
* current value of 'cachingProvider'
*/
public CachingProvider getCachingProvider() {
if (cachingProvider == null) {
throw new IllegalStateException("Cannot initialize caches, cacheProvider not provided");
}
return cachingProvider;
}
/**
* Initialize cache provider.
*
* @param provider
* target cache provider
*/
public void setCachingProvider(CachingProvider provider) {
this.cachingProvider = provider;
initCaches();
}
/**
* Getter accessor for attribute 'cacheManager'.
*
* @return
* current value of 'cacheManager'
*/
public CacheManager getCacheManager() {
if (cacheManager == null) {
throw new IllegalArgumentException("Cache manager must not be null");
}
return cacheManager;
}
}