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

org.apache.geode.management.internal.cli.functions.RegionCreateFunction Maven / Gradle / Ivy

Go to download

Apache Geode provides a database-like consistency model, reliable transaction processing and a shared-nothing architecture to maintain very low latency performance with high concurrency processing

There is a newer version: 1.15.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.management.internal.cli.functions;

import java.util.Set;

import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.internal.lang.StringUtils;
import org.apache.logging.log4j.Logger;

import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.CacheListener;
import org.apache.geode.cache.CacheLoader;
import org.apache.geode.cache.CacheWriter;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.PartitionAttributes;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.PartitionResolver;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionExistsException;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.execute.FunctionAdapter;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.cache.execute.ResultSender;
import org.apache.geode.compression.Compressor;
import org.apache.geode.internal.InternalEntity;
import org.apache.geode.internal.cache.xmlcache.CacheXml;
import org.apache.geode.internal.i18n.LocalizedStrings;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.management.internal.cli.CliUtil;
import org.apache.geode.management.internal.cli.commands.CreateAlterDestroyRegionCommands;
import org.apache.geode.management.internal.cli.exceptions.CreateSubregionException;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.util.RegionPath;
import org.apache.geode.management.internal.configuration.domain.XmlEntity;

/**
 *
 * @since GemFire 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 resultSender = context.getResultSender();

    Cache cache = CacheFactory.getAnyInstance();
    String memberNameOrId =
        CliUtil.getMemberNameOrId(cache.getDistributedSystem().getDistributedMember());

    RegionFunctionArgs regionCreateArgs = (RegionFunctionArgs) context.getArguments();

    if (regionCreateArgs.isSkipIfExists()) {
      Region 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  Region createRegion(Cache cache, RegionFunctionArgs regionCreateArgs) {
    Region 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 factory = null;
    RegionAttributes 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 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 keyConstraintClass =
          CliUtil.forName(keyConstraint, CliStrings.CREATE_REGION__KEYCONSTRAINT);
      factory.setKeyConstraint(keyConstraintClass);
    }

    if (valueConstraint != null && !valueConstraint.isEmpty()) {
      Class valueConstraintClass =
          CliUtil.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 gatewaySenderIds = regionCreateArgs.getGatewaySenderIds();
    if (gatewaySenderIds != null && !gatewaySenderIds.isEmpty()) {
      for (String gatewaySenderId : gatewaySenderIds) {
        factory.addGatewaySenderId(gatewaySenderId);
      }
    }

    // Async Queue Ids
    final Set 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());
    }

    // multicast enabled for replication
    if (regionCreateArgs.isSetMcastEnabled()) {
      factory.setMulticastEnabled(regionCreateArgs.isMcastEnabled());
    }

    // Set plugins
    final Set cacheListeners = regionCreateArgs.getCacheListeners();
    if (cacheListeners != null && !cacheListeners.isEmpty()) {
      for (String cacheListener : cacheListeners) {
        Class> cacheListenerKlass =
            CliUtil.forName(cacheListener, CliStrings.CREATE_REGION__CACHELISTENER);
        factory.addCacheListener(
            CliUtil.newInstance(cacheListenerKlass, CliStrings.CREATE_REGION__CACHELISTENER));
      }
    }

    // Compression provider
    if (regionCreateArgs.isSetCompressor()) {
      Class compressorKlass =
          CliUtil.forName(regionCreateArgs.getCompressor(), CliStrings.CREATE_REGION__COMPRESSOR);
      factory.setCompressor(
          CliUtil.newInstance(compressorKlass, CliStrings.CREATE_REGION__COMPRESSOR));
    }

    final String cacheLoader = regionCreateArgs.getCacheLoader();
    if (cacheLoader != null) {
      Class> cacheLoaderKlass =
          CliUtil.forName(cacheLoader, CliStrings.CREATE_REGION__CACHELOADER);
      factory.setCacheLoader(
          CliUtil.newInstance(cacheLoaderKlass, CliStrings.CREATE_REGION__CACHELOADER));
    }

    final String cacheWriter = regionCreateArgs.getCacheWriter();
    if (cacheWriter != null) {
      Class> cacheWriterKlass =
          CliUtil.forName(cacheWriter, CliStrings.CREATE_REGION__CACHEWRITER);
      factory.setCacheWriter(
          CliUtil.newInstance(cacheWriterKlass, CliStrings.CREATE_REGION__CACHEWRITER));
    }

    String regionName = regionPathData.getName();

    if (parentRegion != null) {
      createdRegion = factory.createSubregion(parentRegion, regionName);
    } else {
      createdRegion = factory.create(regionName);
    }

    return createdRegion;
  }

  @SuppressWarnings("unchecked")
  private static  PartitionAttributes extractPartitionAttributes(Cache cache,
      RegionAttributes regionAttributes, RegionFunctionArgs regionCreateArgs) {
    RegionFunctionArgs.PartitionArgs partitionArgs = regionCreateArgs.getPartitionArgs();

    PartitionAttributesFactory prAttrFactory = null;

    PartitionAttributes partitionAttributes = regionAttributes.getPartitionAttributes();
    if (partitionAttributes != null) {
      prAttrFactory = new PartitionAttributesFactory(partitionAttributes);
    } else {
      prAttrFactory = new PartitionAttributesFactory();
    }

    String colocatedWith = partitionArgs.getPrColocatedWith();
    if (colocatedWith != null) {
      Region 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());
    }

    if (regionCreateArgs.isPartitionResolverSet()) {
      Class partitionResolverClass = forName(
          regionCreateArgs.getPartitionResolver(), CliStrings.CREATE_REGION__PARTITION_RESOLVER);
      prAttrFactory
          .setPartitionResolver((PartitionResolver) newInstance(partitionResolverClass,
              CliStrings.CREATE_REGION__PARTITION_RESOLVER));
    }
    return prAttrFactory.create();
  }


  private static Class forName(String className, String neededFor) {
    if (StringUtils.isBlank(className)) {
      throw new IllegalArgumentException(
          CliStrings.format(CliStrings.CREATE_REGION__MSG__INVALID_PARTITION_RESOLVER,
              new Object[] {className, neededFor}));
    }
    try {
      return (Class) ClassPathLoader.getLatest().forName(className);
    } catch (ClassNotFoundException e) {
      throw new RuntimeException(CliStrings.format(
          CliStrings.CREATE_REGION_PARTITION_RESOLVER__MSG__COULDNOT_FIND_CLASS_0_SPECIFIED_FOR_1,
          new Object[] {className, neededFor}), e);
    } catch (ClassCastException e) {
      throw new RuntimeException(CliStrings.format(
          CliStrings.CREATE_REGION__MSG__PARTITION_RESOLVER__CLASS_0_SPECIFIED_FOR_1_IS_NOT_OF_EXPECTED_TYPE,
          new Object[] {className, neededFor}), e);
    }
  }

  private static PartitionResolver newInstance(Class klass, String neededFor) {
    try {
      return klass.newInstance();
    } catch (InstantiationException e) {
      throw new RuntimeException(CliStrings.format(
          CliStrings.CREATE_REGION__MSG__PARTITION_RESOLVER__COULDNOT_INSTANTIATE_CLASS_0_SPECIFIED_FOR_1,
          new Object[] {klass, neededFor}), e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(CliStrings.format(
          CliStrings.CREATE_REGION__MSG__PARTITION_RESOLVER__COULDNOT_ACCESS_CLASS_0_SPECIFIED_FOR_1,
          new Object[] {klass, neededFor}), e);
    }
  }

  @Override
  public String getId() {
    return ID;
  }
}