blob: 74afc4716de6fc1698f739182f5435550cc3ca65 [file] [log] [blame]
/*
* ========================================================================
* Copyright (c) 2002-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
* more patents listed at http://www.pivotal.io/patents.
* ========================================================================
*/
package com.gemstone.gemfire.management.internal.cli.functions;
import java.util.Set;
import org.apache.logging.log4j.Logger;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.CacheListener;
import com.gemstone.gemfire.cache.CacheLoader;
import com.gemstone.gemfire.cache.CacheWriter;
import com.gemstone.gemfire.cache.DataPolicy;
import com.gemstone.gemfire.cache.PartitionAttributes;
import com.gemstone.gemfire.cache.PartitionAttributesFactory;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.RegionExistsException;
import com.gemstone.gemfire.cache.RegionFactory;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.execute.FunctionAdapter;
import com.gemstone.gemfire.cache.execute.FunctionContext;
import com.gemstone.gemfire.cache.execute.ResultSender;
import com.gemstone.gemfire.compression.Compressor;
import com.gemstone.gemfire.internal.ClassPathLoader;
import com.gemstone.gemfire.internal.InternalEntity;
import com.gemstone.gemfire.internal.cache.xmlcache.CacheXml;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.logging.LogService;
import com.gemstone.gemfire.management.internal.cli.CliUtil;
import com.gemstone.gemfire.management.internal.cli.commands.CreateAlterDestroyRegionCommands;
import com.gemstone.gemfire.management.internal.cli.exceptions.CreateSubregionException;
import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings;
import com.gemstone.gemfire.management.internal.cli.util.RegionPath;
import com.gemstone.gemfire.management.internal.configuration.domain.XmlEntity;
/**
*
* @author Abhishek Chaudhari
* @since 7.0
*/
public class RegionCreateFunction extends FunctionAdapter implements InternalEntity {
private static final Logger logger = LogService.getLogger();
private static final long serialVersionUID = 8746830191680509335L;
private static final String ID = RegionCreateFunction.class.getName();
public static RegionCreateFunction INSTANCE = new RegionCreateFunction();
@Override
public boolean isHA() {
return false;
}
@Override
public void execute(FunctionContext context) {
ResultSender<Object> resultSender = context.getResultSender();
Cache cache = CacheFactory.getAnyInstance();
String memberNameOrId = CliUtil.getMemberNameOrId(cache.getDistributedSystem().getDistributedMember());
RegionFunctionArgs regionCreateArgs = (RegionFunctionArgs) context.getArguments();
if (regionCreateArgs.isSkipIfExists()) {
Region<Object, Object> region = cache.getRegion(regionCreateArgs.getRegionPath());
if (region != null) {
resultSender.lastResult(new CliFunctionResult(memberNameOrId, true, CliStrings.format(CliStrings.CREATE_REGION__MSG__SKIPPING_0_REGION_PATH_1_ALREADY_EXISTS, new Object[] {memberNameOrId, regionCreateArgs.getRegionPath()})));
return;
}
}
try {
Region<?, ?> createdRegion = createRegion(cache, regionCreateArgs);
XmlEntity xmlEntity = new XmlEntity(CacheXml.REGION, "name", createdRegion.getName());
resultSender.lastResult(new CliFunctionResult(memberNameOrId, xmlEntity, CliStrings.format(CliStrings.CREATE_REGION__MSG__REGION_0_CREATED_ON_1, new Object[] {createdRegion.getFullPath(), memberNameOrId})));
} catch (IllegalStateException e) {
String exceptionMsg = e.getMessage();
String localizedString = LocalizedStrings.DiskStore_IS_USED_IN_NONPERSISTENT_REGION.toLocalizedString();
if (localizedString.equals(e.getMessage())) {
exceptionMsg = exceptionMsg
+ " " + CliStrings.format(CliStrings.CREATE_REGION__MSG__USE_ONE_OF_THESE_SHORTCUTS_0,
new Object[] { String.valueOf(CreateAlterDestroyRegionCommands.PERSISTENT_OVERFLOW_SHORTCUTS)});
}
resultSender.lastResult(handleException(memberNameOrId, exceptionMsg, null/*do not log*/));
} catch (IllegalArgumentException e) {
resultSender.lastResult(handleException(memberNameOrId, e.getMessage(), e));
} catch (RegionExistsException e) {
String exceptionMsg = CliStrings.format(CliStrings.CREATE_REGION__MSG__REGION_PATH_0_ALREADY_EXISTS_ON_1, new Object[] {regionCreateArgs.getRegionPath(), memberNameOrId});
resultSender.lastResult(handleException(memberNameOrId, exceptionMsg, e));
} catch (CreateSubregionException e) {
resultSender.lastResult(handleException(memberNameOrId, e.getMessage(), e));
} catch (Exception e) {
String exceptionMsg = e.getMessage();
if (exceptionMsg == null) {
exceptionMsg = CliUtil.stackTraceAsString(e);
}
resultSender.lastResult(handleException(memberNameOrId, exceptionMsg, e));
}
}
private CliFunctionResult handleException(final String memberNameOrId,
final String exceptionMsg, final Exception e) {
if (e != null && logger.isDebugEnabled()) {
logger.debug(e.getMessage(), e);
}
if (exceptionMsg != null) {
return new CliFunctionResult(memberNameOrId, false, exceptionMsg);
}
return new CliFunctionResult(memberNameOrId);
}
public static <K, V> Region<?, ?> createRegion(Cache cache, RegionFunctionArgs regionCreateArgs) {
Region<K, V> createdRegion = null;
final String regionPath = regionCreateArgs.getRegionPath();
final RegionShortcut regionShortcut = regionCreateArgs.getRegionShortcut();
final String useAttributesFrom = regionCreateArgs.getUseAttributesFrom();
// If a region path indicates a sub-region, check whether the parent region exists
RegionPath regionPathData = new RegionPath(regionPath);
String parentRegionPath = regionPathData.getParent();
Region<?, ?> parentRegion = null;
if (parentRegionPath != null && !Region.SEPARATOR.equals(parentRegionPath)) {
parentRegion = cache.getRegion(parentRegionPath);
if (parentRegion == null) {
throw new IllegalArgumentException(CliStrings.format(CliStrings.CREATE_REGION__MSG__PARENT_REGION_FOR_0_DOESNOT_EXIST, new Object[] {regionPath}));
}
if (parentRegion.getAttributes().getPartitionAttributes() != null) {
// For a PR, sub-regions are not supported.
throw new CreateSubregionException(
CliStrings.format(CliStrings.CREATE_REGION__MSG__0_IS_A_PR_CANNOT_HAVE_SUBREGIONS, parentRegion.getFullPath()));
}
}
// One of Region Shortcut OR Use Attributes From has to be given
if (regionShortcut == null && useAttributesFrom == null) {
throw new IllegalArgumentException(CliStrings.CREATE_REGION__MSG__ONE_OF_REGIONSHORTCUT_AND_USEATTRIBUESFROM_IS_REQUIRED);
}
boolean isPartitioned = false;
RegionFactory<K, V> factory = null;
RegionAttributes<K, V> regionAttributes = null;
if (regionShortcut != null) {
regionAttributes = cache.getRegionAttributes(regionShortcut.toString());
if (logger.isDebugEnabled()) {
logger.debug("Using shortcut {} for {} region attributes : {}", regionShortcut, regionPath, regionAttributes);
}
if (regionAttributes == null) {
if (logger.isDebugEnabled()) {
logger.debug("Shortcut {} doesn't have attributes in {}", regionShortcut, cache.listRegionAttributes());
}
throw new IllegalStateException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_LOAD_REGION_ATTRIBUTES_FOR_SHORTCUT_0, regionShortcut));
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Using Manager's region attributes for {}", regionPath);
}
regionAttributes = regionCreateArgs.getRegionAttributes();
if (logger.isDebugEnabled()) {
logger.debug("Using Attributes : {}", regionAttributes);
}
}
isPartitioned = regionAttributes.getPartitionAttributes() != null;
factory = cache.createRegionFactory(regionAttributes);
if (!isPartitioned && regionCreateArgs.hasPartitionAttributes()) {
throw new IllegalArgumentException(
CliStrings.format(
CliStrings.CREATE_REGION__MSG__OPTION_0_CAN_BE_USED_ONLY_FOR_PARTITIONEDREGION,
regionCreateArgs.getPartitionArgs().getUserSpecifiedPartitionAttributes()));
}
if (isPartitioned) {
PartitionAttributes<K, V> partitionAttributes = extractPartitionAttributes(cache, regionAttributes, regionCreateArgs);
DataPolicy originalDataPolicy = regionAttributes.getDataPolicy();
factory.setPartitionAttributes(partitionAttributes);
// We have to do this because AttributesFactory.setPartitionAttributes()
// checks RegionAttributes.hasDataPolicy() which is set only when the data
// policy is set explicitly
factory.setDataPolicy(originalDataPolicy);
}
// Set Constraints
final String keyConstraint = regionCreateArgs.getKeyConstraint();
final String valueConstraint = regionCreateArgs.getValueConstraint();
if (keyConstraint != null && !keyConstraint.isEmpty()) {
Class<K> keyConstraintClass = forName(keyConstraint, CliStrings.CREATE_REGION__KEYCONSTRAINT);
factory.setKeyConstraint(keyConstraintClass);
}
if (valueConstraint != null && !valueConstraint.isEmpty()) {
Class<V> valueConstraintClass = forName(valueConstraint, CliStrings.CREATE_REGION__VALUECONSTRAINT);
factory.setValueConstraint(valueConstraintClass);
}
// Expiration attributes
final RegionFunctionArgs.ExpirationAttrs entryExpirationIdleTime = regionCreateArgs.getEntryExpirationIdleTime();
if (entryExpirationIdleTime != null) {
factory.setEntryIdleTimeout(entryExpirationIdleTime.convertToExpirationAttributes());
}
final RegionFunctionArgs.ExpirationAttrs entryExpirationTTL = regionCreateArgs.getEntryExpirationTTL();
if (entryExpirationTTL != null) {
factory.setEntryTimeToLive(entryExpirationTTL.convertToExpirationAttributes());
}
final RegionFunctionArgs.ExpirationAttrs regionExpirationIdleTime = regionCreateArgs.getRegionExpirationIdleTime();
if (regionExpirationIdleTime != null) {
factory.setEntryIdleTimeout(regionExpirationIdleTime.convertToExpirationAttributes());
}
final RegionFunctionArgs.ExpirationAttrs regionExpirationTTL = regionCreateArgs.getRegionExpirationTTL();
if (regionExpirationTTL != null) {
factory.setEntryTimeToLive(regionExpirationTTL.convertToExpirationAttributes());
}
// Associate a Disk Store
final String diskStore = regionCreateArgs.getDiskStore();
if (diskStore != null && !diskStore.isEmpty()) {
factory.setDiskStoreName(diskStore);
}
if (regionCreateArgs.isSetDiskSynchronous()) {
factory.setDiskSynchronous(regionCreateArgs.isDiskSynchronous());
}
if (regionCreateArgs.isSetOffHeap()) {
factory.setOffHeap(regionCreateArgs.isOffHeap());
}
// Set stats enabled
if (regionCreateArgs.isSetStatisticsEnabled()) {
factory.setStatisticsEnabled(regionCreateArgs.isStatisticsEnabled());
}
// Set conflation
if (regionCreateArgs.isSetEnableAsyncConflation()) {
factory.setEnableAsyncConflation(regionCreateArgs.isEnableAsyncConflation());
}
if (regionCreateArgs.isSetEnableSubscriptionConflation()) {
factory.setEnableSubscriptionConflation(regionCreateArgs.isEnableSubscriptionConflation());
}
// Gateway Sender Ids
final Set<String> gatewaySenderIds = regionCreateArgs.getGatewaySenderIds();
if (gatewaySenderIds != null && !gatewaySenderIds.isEmpty()) {
for (String gatewaySenderId : gatewaySenderIds) {
factory.addGatewaySenderId(gatewaySenderId);
}
}
// Async Queue Ids
final Set<String> asyncEventQueueIds = regionCreateArgs.getAsyncEventQueueIds();
if (asyncEventQueueIds != null && !asyncEventQueueIds.isEmpty()) {
for (String asyncEventQueueId : asyncEventQueueIds) {
factory.addAsyncEventQueueId(asyncEventQueueId);
}
}
// concurrency check enabled & concurrency level
if (regionCreateArgs.isSetConcurrencyChecksEnabled()) {
factory.setConcurrencyChecksEnabled(regionCreateArgs.isConcurrencyChecksEnabled());
}
if (regionCreateArgs.isSetConcurrencyLevel()) {
factory.setConcurrencyLevel(regionCreateArgs.getConcurrencyLevel());
}
// cloning enabled for delta
if (regionCreateArgs.isSetCloningEnabled()) {
factory.setCloningEnabled(regionCreateArgs.isCloningEnabled());
}
// Set plugins
final Set<String> cacheListeners = regionCreateArgs.getCacheListeners();
if (cacheListeners != null && !cacheListeners.isEmpty()) {
for (String cacheListener : cacheListeners) {
Class<CacheListener<K, V>> cacheListenerKlass = forName(cacheListener, CliStrings.CREATE_REGION__CACHELISTENER);
factory.addCacheListener(newInstance(cacheListenerKlass, CliStrings.CREATE_REGION__CACHELISTENER));
}
}
// Compression provider
if(regionCreateArgs.isSetCompressor()) {
Class<Compressor> compressorKlass = forName(regionCreateArgs.getCompressor(), CliStrings.CREATE_REGION__COMPRESSOR);
factory.setCompressor(newInstance(compressorKlass, CliStrings.CREATE_REGION__COMPRESSOR));
}
final String cacheLoader = regionCreateArgs.getCacheLoader();
if (cacheLoader != null) {
Class<CacheLoader<K, V>> cacheLoaderKlass = forName(cacheLoader, CliStrings.CREATE_REGION__CACHELOADER);
factory.setCacheLoader(newInstance(cacheLoaderKlass, CliStrings.CREATE_REGION__CACHELOADER));
}
final String cacheWriter = regionCreateArgs.getCacheWriter();
if (cacheWriter != null) {
Class<CacheWriter<K, V>> cacheWriterKlass = forName(cacheWriter, CliStrings.CREATE_REGION__CACHEWRITER);
factory.setCacheWriter(newInstance(cacheWriterKlass, CliStrings.CREATE_REGION__CACHEWRITER));
}
String regionName = regionPathData.getName();
final String hdfsStoreName = regionCreateArgs.getHDFSStoreName();
if (hdfsStoreName != null && !hdfsStoreName.isEmpty()) {
factory.setHDFSStoreName(hdfsStoreName);
}
if (regionCreateArgs.isSetHDFSWriteOnly()) {
factory.setHDFSWriteOnly(regionCreateArgs.getHDFSWriteOnly());
}
if (parentRegion != null) {
createdRegion = factory.createSubregion(parentRegion, regionName);
} else {
createdRegion = factory.create(regionName);
}
return createdRegion;
}
@SuppressWarnings("unchecked")
private static <K, V> PartitionAttributes<K, V> extractPartitionAttributes(Cache cache, RegionAttributes<K, V> regionAttributes, RegionFunctionArgs regionCreateArgs) {
RegionFunctionArgs.PartitionArgs partitionArgs = regionCreateArgs.getPartitionArgs();
PartitionAttributesFactory<K, V> prAttrFactory = null;
PartitionAttributes<K, V> partitionAttributes = regionAttributes.getPartitionAttributes();
if (partitionAttributes != null) {
prAttrFactory = new PartitionAttributesFactory<K, V>(partitionAttributes);
} else {
prAttrFactory = new PartitionAttributesFactory<K, V>();
}
String colocatedWith = partitionArgs.getPrColocatedWith();
if (colocatedWith != null) {
Region<Object, Object> colocatedWithRegion = cache.getRegion(colocatedWith);
if (colocatedWithRegion == null) {
throw new IllegalArgumentException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COLOCATEDWITH_REGION_0_DOESNOT_EXIST, colocatedWith));
}
if (!colocatedWithRegion.getAttributes().getDataPolicy().withPartitioning()) {
throw new IllegalArgumentException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COLOCATEDWITH_REGION_0_IS_NOT_PARTITIONEDREGION, colocatedWith));
}
prAttrFactory.setColocatedWith(colocatedWith);
}
if (partitionArgs.isSetPRLocalMaxMemory()) {
prAttrFactory.setLocalMaxMemory(partitionArgs.getPrLocalMaxMemory());
}
if (partitionArgs.isSetPRTotalMaxMemory()) {
prAttrFactory.setTotalMaxMemory(partitionArgs.getPrTotalMaxMemory());
}
if (partitionArgs.isSetPRTotalNumBuckets()) {
prAttrFactory.setTotalNumBuckets(partitionArgs.getPrTotalNumBuckets());
}
if (partitionArgs.isSetPRRedundantCopies()) {
prAttrFactory.setRedundantCopies(partitionArgs.getPrRedundantCopies());
}
if (partitionArgs.isSetPRRecoveryDelay()) {
prAttrFactory.setRecoveryDelay(partitionArgs.getPrRecoveryDelay());
}
if (partitionArgs.isSetPRStartupRecoveryDelay()) {
prAttrFactory.setStartupRecoveryDelay(partitionArgs.getPrStartupRecoveryDelay());
}
return prAttrFactory.create();
}
@SuppressWarnings("unchecked")
private static <K> Class<K> forName(String classToLoadName, String neededFor) {
Class<K> loadedClass = null;
try {
// Set Constraints
ClassPathLoader classPathLoader = ClassPathLoader.getLatest();
if (classToLoadName != null && !classToLoadName.isEmpty()) {
loadedClass = (Class<K>) classPathLoader.forName(classToLoadName);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_FIND_CLASS_0_SPECIFIED_FOR_1, new Object[] {classToLoadName, neededFor}), e);
} catch (ClassCastException e) {
throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__CLASS_SPECIFIED_FOR_0_SPECIFIED_FOR_1_IS_NOT_OF_EXPECTED_TYPE, new Object[] {classToLoadName, neededFor}), e);
}
return loadedClass;
}
private static <K> K newInstance(Class<K> klass, String neededFor) {
K instance = null;
try {
instance = klass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_INSTANTIATE_CLASS_0_SPECIFIED_FOR_1, new Object[] {klass, neededFor}), e);
} catch (IllegalAccessException e) {
throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_ACCESS_CLASS_0_SPECIFIED_FOR_1, new Object[] {klass, neededFor}), e);
}
return instance;
}
@Override
public String getId() {
return ID;
}
}