blob: 9e38d7f723503c892c5c1c8cf21336758d379958 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.modules.hibernate;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.execute.FunctionService;
import com.gemstone.gemfire.distributed.DistributedLockService;
import com.gemstone.gemfire.internal.logging.LogService;
import com.gemstone.gemfire.modules.util.CreateRegionFunction;
import com.gemstone.gemfire.modules.util.RegionConfiguration;
import org.apache.logging.log4j.Logger;
import org.hibernate.cache.Cache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.CacheProvider;
import org.hibernate.cache.Timestamper;
import java.util.Iterator;
import java.util.Properties;
@SuppressWarnings("deprecation")
public class GemFireCacheProvider implements CacheProvider {
private static final Logger logger = LogService.getLogger();
protected com.gemstone.gemfire.cache.Cache _cache;
private DistributedLockService distributedLockService;
private Properties regionAttributes = new Properties();
private final String DEFAULT_REGION_TYPE = RegionShortcut.REPLICATE_HEAP_LRU
.name();
private final String HIBERNATE_DLOCK_SERVICE_NAME = "hibernate-cache-lock-service";
/**
* Configure the cache
*
* @param regionName
* the name of the cache region
* @param properties
* configuration settings
* @throws CacheException
*/
public Cache buildCache(String regionName, Properties properties)
throws CacheException {
logger.info("GemFireCacheProvider: Creating cache: " + regionName);
Region region = retrieveOrCreateRegion(regionName);
Cache cache = null;
if (region == null) {
// Doh, blow up
throw new RuntimeException("Couldn't find cache region : " + regionName);
}
else {
cache = new GemFireCache(region, this.distributedLockService);
}
logger.info("GemFireCacheProvider: Created cache: " + regionName + "->" + cache);
return cache;
}
public boolean isMinimalPutsEnabledByDefault() {
return false;
}
/**
* Generate a timestamp
*/
public long nextTimestamp() {
return Timestamper.next();
}
/**
* Returns the region if already created, otherwise first tries to create it
* from cache.xml, if not specified in cache.xml, create the region from the
* properties specified in hibernate.cfg.xml. Two types of properties can be
* specified in hibernate.cfg.xml
* <ol>
* <li>gemfire.default-region-attributes-id: the default region type to
* create. (default value for this is REPLICATE)
* <li>gemfire.region-attributes-for:fullyQualifiedRegionName when a region
* wants to override the default region type
* </ol>
*
* @param regionName
* @return the region
*/
protected Region retrieveOrCreateRegion(String regionName) {
// TODO client regions
Region r = _cache.getRegion(regionName);
if (r == null) {
String regionType = getRegionType(regionName);
r = _cache.createRegionFactory(RegionShortcut.valueOf(regionType))
.create(regionName);
RegionConfiguration regionConfig = new RegionConfiguration();
regionConfig.setRegionName(regionName);
regionConfig.setRegionAttributesId(regionType);
FunctionService.onMembers(_cache.getDistributedSystem())
.withArgs(regionConfig).execute(CreateRegionFunction.ID).getResult();
}
return r;
}
/**
* returns the type of region to create by consulting the properties specified
* in hibernate.cfg.xml
*
* @see #retrieveOrCreateRegion(String)
* @param regionName
* @return string representation of {@link RegionShortcut}
*/
private String getRegionType(String regionName) {
String rType = regionAttributes
.getProperty("gemfire.default-region-attributes-id");
if (rType == null) {
rType = DEFAULT_REGION_TYPE;
}
// iterate to find overridden property for a region
Iterator<Object> it = regionAttributes.keySet().iterator();
while (it.hasNext()) {
String current = (String)it.next();
if (current.contains(regionName)) {
rType = regionAttributes.getProperty(current);
break;
}
}
return rType.toUpperCase();
}
/**
* Callback to perform any necessary initialization of the underlying cache
* implementation during SessionFactory construction.
*
* @param properties
* current configuration settings.
*/
public void start(Properties properties) throws CacheException {
logger.info("GemFireCacheProvider: Creating cache provider");
// We have to strip out any unknown properties, do so here
Properties gemfireOnlyProperties = new Properties();
for (Object keyObj : properties.keySet()) {
String key = (String)keyObj;
if (key.contains("region-attributes")) {
regionAttributes.put(key, properties.get(key));
}
else if (key.startsWith("gemfire.")) {
gemfireOnlyProperties.setProperty(key.replace("gemfire.", ""),
properties.getProperty(key));
}
}
// Create cache and d-lock service
try {
_cache = new CacheFactory(gemfireOnlyProperties).create();
DistributedLockService existing = DistributedLockService.getServiceNamed(HIBERNATE_DLOCK_SERVICE_NAME);
if (existing == null) {
this.distributedLockService = DistributedLockService.create(
HIBERNATE_DLOCK_SERVICE_NAME, _cache.getDistributedSystem());
} else {
this.distributedLockService = existing;
}
}
catch (com.gemstone.gemfire.cache.CacheException e) {
throw new CacheException(e);
}
FunctionService.registerFunction(new CreateRegionFunction());
logger.info("GemFireCacheProvider: Done creating cache provider");
}
/**
* Callback to perform any necessary cleanup of the underlying cache
* implementation during SessionFactory.close().
*/
public void stop() {
logger.info("GemFireCacheProvider: Stopping");
_cache.close();
logger.info("GemFireCacheProvider: Stopped");
}
public static Logger getLogger() {
return logger;
}
}