blob: c2fa3bab2f3d7a9fcf4d33d46f2903d9c6540c0a [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.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.StringTokenizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.ClientCacheFactory;
import com.gemstone.gemfire.cache.client.ClientRegionFactory;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import com.gemstone.gemfire.cache.execute.FunctionService;
import com.gemstone.gemfire.modules.util.BootstrappingFunction;
import com.gemstone.gemfire.modules.util.CreateRegionFunction;
import com.gemstone.gemfire.modules.util.RegionConfiguration;
public class ClientServerRegionFactoryDelegate extends RegionFactoryDelegate {
private static final String DEFAULT_SERVER_REGION_TYPE = RegionShortcut.PARTITION.name();
private static final String DEFAULT_CLIENT_REGION_TYPE = ClientRegionShortcut.PROXY.name();
private ClientCache clientCache;
public ClientServerRegionFactoryDelegate(Properties gemfireProperties,
Properties regionProperties) {
super(gemfireProperties, regionProperties);
}
@Override
public GemFireCache startCache() {
log.info("Creating a GemFire client cache");
String locatorsString = (String)gemfireProperties.remove("locators");
checkExistingCache();
ClientCacheFactory ccf = new ClientCacheFactory(gemfireProperties).setPoolSubscriptionEnabled(true);
List<LocatorHolder> locators = getLocatorsMap(locatorsString);
for (LocatorHolder locHolder : locators) {
log.debug("adding pool locator with host {} port {}", locHolder.host, locHolder.port);
ccf.addPoolLocator(locHolder.host, locHolder.port);
}
this.clientCache = ccf.create();
log.debug("GemFire client cache creation completed");
// bootstrap the servers
FunctionService.onServers(this.clientCache).execute(new BootstrappingFunction()).getResult();
FunctionService.registerFunction(new CreateRegionFunction(this.clientCache));
return this.clientCache;
}
private List<LocatorHolder> getLocatorsMap(String locatorsString) {
List<LocatorHolder> retval = new ArrayList<LocatorHolder>();
if (locatorsString == null || locatorsString.isEmpty()) {
return retval;
}
StringTokenizer st = new StringTokenizer(locatorsString, ",");
while (st.hasMoreTokens()) {
String locator = st.nextToken();
int portIndex = locator.indexOf('[');
if (portIndex < 1) {
portIndex = locator.lastIndexOf(':');
}
// starting in 5.1.0.4 we allow '@' as the bind-addr separator
// to let people use IPv6 numeric addresses (which contain colons)
int bindAddrIdx = locator.lastIndexOf('@', portIndex - 1);
if (bindAddrIdx < 0) {
bindAddrIdx = locator.lastIndexOf(':', portIndex - 1);
}
String host = locator.substring(0,
bindAddrIdx > -1 ? bindAddrIdx : portIndex);
if (host.indexOf(':') >= 0) {
bindAddrIdx = locator.lastIndexOf('@');
host = locator.substring(0, bindAddrIdx > -1 ? bindAddrIdx : portIndex);
}
int lastIndex = locator.lastIndexOf(']');
if (lastIndex == -1) {
if (locator.indexOf('[') >= 0) {
throw new IllegalArgumentException("Invalid locator");
} else {
// Using host:port syntax
lastIndex = locator.length();
}
}
String port = locator.substring(portIndex + 1, lastIndex);
int portVal = 0;
try {
portVal = Integer.parseInt(port);
if (portVal < 1 || portVal > 65535) {
throw new IllegalArgumentException("port should be grater than zero and less than 65536");
}
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("Invalid Locator");
}
retval.add(new LocatorHolder(host, portVal));
}
return retval;
}
@Override
public Region<Object, EntityWrapper> createRegion(String regionName) {
// first create the region on the server
String serverRegionType = getServerRegionType(regionName);
RegionConfiguration regionConfig = new RegionConfiguration();
regionConfig.setRegionName(regionName);
regionConfig.setRegionAttributesId(serverRegionType);
regionConfig.setCacheWriterName(EntityRegionWriter.class.getCanonicalName());
FunctionService.onServer(this.clientCache).withArgs(regionConfig)
.execute(CreateRegionFunction.ID).getResult();
// now create region on the client
Region<Object, EntityWrapper> r = this.clientCache.getRegion(regionName);
if (r != null) {
return r;
}
String clientRegionType = getClientRegionType(regionName);
ClientRegionFactory<Object, EntityWrapper> rf = this.clientCache
.createClientRegionFactory(ClientRegionShortcut
.valueOf(clientRegionType));
r = rf.create(regionName);
return r;
}
private String getClientRegionType(String regionName) {
String rType = getOverridenClientRegionType(regionName);
if (rType != null) {
return rType.toUpperCase();
}
rType = regionProperties.getProperty("gemfire.default-client-region-attributes-id");
if (rType == null) {
rType = DEFAULT_CLIENT_REGION_TYPE;
}
return rType.toUpperCase();
}
private String getServerRegionType(String regionName) {
String rType = getOverridenServerRegionType(regionName);
if (rType != null) {
return rType.toUpperCase();
}
rType = regionProperties.getProperty("gemfire.default-region-attributes-id");
if (rType == null) {
rType = DEFAULT_SERVER_REGION_TYPE;
}
return rType.toUpperCase();
}
private String getOverridenServerRegionType(String regionName) {
String rType = null;
Iterator<Object> it = regionProperties.keySet().iterator();
while (it.hasNext()) {
String current = (String)it.next();
if (current.contains(regionName) && !current.contains("client")) {
rType = regionProperties.getProperty(current);
break;
}
}
return rType;
}
private String getOverridenClientRegionType(String regionName) {
String rType = null;
Iterator<Object> it = regionProperties.keySet().iterator();
while (it.hasNext()) {
String current = (String)it.next();
if (current.contains(regionName) && current.contains("client")) {
rType = regionProperties.getProperty(current);
break;
}
}
return rType;
}
private static class LocatorHolder {
private String host;
private int port;
private LocatorHolder(String host, int port) {
this.host = host;
this.port = port;
}
}
}