/**
   * Intelligently merges the given RegionAttributes with the configuration setting of the
   * RegionFactory. This method is used to merge the RegionAttributes and PartitionAttributes with
   * the RegionFactory that is created when the user specified a RegionShortcut. This method gets
   * called by the createRegionFactory method depending upon the value passed to the
   * Cache.createRegionFactory() method (i.e. whether there was a RegionShortcut specified or not).
   *
   * @param <K> the Class type fo the Region key.
   * @param <V> the Class type of the Region value.
   * @param regionFactory the GemFire RegionFactory used to configure and create the Region that is
   *     the product of this RegionFactoryBean.
   * @param regionAttributes the RegionAttributes containing the Region configuration settings to
   *     merge to the RegionFactory.
   * @return the RegionFactory with the configuration settings of the RegionAttributes merged.
   * @see #isUserSpecifiedEvictionAttributes(com.gemstone.gemfire.cache.RegionAttributes)
   * @see #validateRegionAttributes(com.gemstone.gemfire.cache.RegionAttributes)
   * @see com.gemstone.gemfire.cache.RegionAttributes
   * @see com.gemstone.gemfire.cache.RegionFactory
   */
  @SuppressWarnings("unchecked")
  protected <K, V> RegionFactory<K, V> mergeRegionAttributes(
      final RegionFactory<K, V> regionFactory, final RegionAttributes<K, V> regionAttributes) {

    if (regionAttributes != null) {
      // NOTE this validation may not be strictly required depending on how the RegionAttributes
      // were "created",
      // but...
      validateRegionAttributes(regionAttributes);

      regionFactory.setCloningEnabled(regionAttributes.getCloningEnabled());
      regionFactory.setCompressor(regionAttributes.getCompressor());
      regionFactory.setConcurrencyChecksEnabled(regionAttributes.getConcurrencyChecksEnabled());
      regionFactory.setConcurrencyLevel(regionAttributes.getConcurrencyLevel());
      regionFactory.setCustomEntryIdleTimeout(regionAttributes.getCustomEntryIdleTimeout());
      regionFactory.setCustomEntryTimeToLive(regionAttributes.getCustomEntryTimeToLive());
      regionFactory.setDiskSynchronous(regionAttributes.isDiskSynchronous());
      regionFactory.setEnableAsyncConflation(regionAttributes.getEnableAsyncConflation());
      regionFactory.setEnableSubscriptionConflation(
          regionAttributes.getEnableSubscriptionConflation());
      regionFactory.setEntryIdleTimeout(regionAttributes.getEntryIdleTimeout());
      regionFactory.setEntryTimeToLive(regionAttributes.getEntryTimeToLive());

      // NOTE EvictionAttributes are created by certain RegionShortcuts; need the null check!
      if (isUserSpecifiedEvictionAttributes(regionAttributes)) {
        regionFactory.setEvictionAttributes(regionAttributes.getEvictionAttributes());
      }

      regionFactory.setIgnoreJTA(regionAttributes.getIgnoreJTA());
      regionFactory.setIndexMaintenanceSynchronous(
          regionAttributes.getIndexMaintenanceSynchronous());
      regionFactory.setInitialCapacity(regionAttributes.getInitialCapacity());
      regionFactory.setKeyConstraint(regionAttributes.getKeyConstraint());
      regionFactory.setLoadFactor(regionAttributes.getLoadFactor());
      regionFactory.setLockGrantor(regionAttributes.isLockGrantor());
      regionFactory.setMembershipAttributes(regionAttributes.getMembershipAttributes());
      regionFactory.setMulticastEnabled(regionAttributes.getMulticastEnabled());
      mergePartitionAttributes(regionFactory, regionAttributes);
      regionFactory.setPoolName(regionAttributes.getPoolName());
      regionFactory.setRegionIdleTimeout(regionAttributes.getRegionIdleTimeout());
      regionFactory.setRegionTimeToLive(regionAttributes.getRegionTimeToLive());
      regionFactory.setStatisticsEnabled(regionAttributes.getStatisticsEnabled());
      regionFactory.setSubscriptionAttributes(regionAttributes.getSubscriptionAttributes());
      regionFactory.setValueConstraint(regionAttributes.getValueConstraint());
    }

    return regionFactory;
  }
  @SuppressWarnings("rawtypes")
  @Test
  public void testReplicaWithAttributes() throws Exception {
    assertTrue(context.containsBean("replicated-with-attributes"));
    Region region = context.getBean("replicated-with-attributes", Region.class);
    RegionAttributes attrs = region.getAttributes();

    assertEquals(10, attrs.getInitialCapacity());
    assertEquals(true, attrs.getIgnoreJTA());
    assertEquals(false, attrs.getIndexMaintenanceSynchronous());
    assertEquals(String.class, attrs.getKeyConstraint());
    assertEquals(String.class, attrs.getValueConstraint());
    assertEquals(true, attrs.isDiskSynchronous());
    assertEquals(Scope.GLOBAL, attrs.getScope());
    // assertEquals(true, attrs.isLockGrantor());
    assertEquals(true, attrs.getEnableAsyncConflation());
    assertEquals(true, attrs.getEnableSubscriptionConflation());
    assertEquals(0.50, attrs.getLoadFactor(), 0.001);
    assertEquals(false, attrs.getCloningEnabled());
    assertEquals(10, attrs.getConcurrencyLevel());
    assertEquals(true, attrs.getMulticastEnabled());
  }
  public RegionAttributesInfo(RegionAttributes<?, ?> ra) {

    cloningEnabled = ra.getCloningEnabled();
    concurrencyChecksEnabled = ra.getConcurrencyChecksEnabled();
    concurrencyLevel = ra.getConcurrencyLevel();
    dataPolicy = ra.getDataPolicy();
    diskStoreName = ra.getDiskStoreName();
    enableAsyncConflation = ra.getEnableAsyncConflation();
    enableGateway = ra.getEnableGateway();
    enableSubscriptionConflation = ra.getEnableSubscriptionConflation();
    gatewayHubId = ra.getGatewayHubId();
    ignoreJTA = ra.getIgnoreJTA();
    indexMaintenanceSynchronous = ra.getIndexMaintenanceSynchronous();
    initialCapacity = ra.getInitialCapacity();
    loadFactor = ra.getLoadFactor();
    multicastEnabled = ra.getMulticastEnabled();
    poolName = ra.getPoolName();
    scope = ra.getScope();
    statisticsEnabled = ra.getStatisticsEnabled();
    entryTimeToLive = ra.getEntryTimeToLive().getTimeout();
    isLockGrantor = ra.isLockGrantor();
    entryIdleTimeout = ra.getEntryIdleTimeout().getTimeout();
    regionIdleTimeout = ra.getRegionIdleTimeout().getTimeout();
    regionTimeToLive = ra.getRegionTimeToLive().getTimeout();

    Compressor compressor = ra.getCompressor();
    if (compressor != null) {
      compressorClassName = compressor.getClass().getCanonicalName();
    }

    ExpirationAction expAction = ra.getEntryIdleTimeout().getAction();
    if (expAction != null) {
      entryIdleTimeoutAction = expAction.toString();
    }

    expAction = ra.getEntryTimeToLive().getAction();
    if (expAction != null) {
      entryTimeToLiveAction = expAction.toString();
    }

    expAction = ra.getRegionTimeToLive().getAction();

    if (expAction != null) {
      regionTimeToLiveAction = expAction.toString();
    }

    expAction = ra.getRegionIdleTimeout().getAction();
    if (expAction != null) {
      regionIdleTimeoutAction = expAction.toString();
    }

    // Collecting information about all the CacheListeners, CacheWriters, CacheLoaders
    CacheListener<?, ?>[] cacheListeners = ra.getCacheListeners();

    // TODO: The cacheListeners should be added one by one by delimited by a "\n"
    if (cacheListeners.length > 0) {
      cacheListenerClassNames = new ArrayList<String>();
      for (CacheListener<?, ?> cacheListener : cacheListeners) {
        cacheListenerClassNames.add(cacheListener.getClass().getCanonicalName());
      }
      Collections.sort(cacheListenerClassNames);
    }

    // CacheLoader
    CacheLoader<?, ?> cacheLoader = ra.getCacheLoader();

    if (cacheLoader != null) {
      cacheLoaderClassName = cacheLoader.getClass().getCanonicalName();
    }

    // CacheWriter
    CacheWriter<?, ?> cacheWriter = ra.getCacheWriter();

    if (cacheWriter != null) {
      cacheWriterClassName = cacheWriter.getClass().getCanonicalName();
    }

    // Setting the Partition Attributes and Eviction Attributes
    PartitionAttributes<?, ?> partitionAttributes = ra.getPartitionAttributes();
    EvictionAttributes evictionAttributes = ra.getEvictionAttributes();

    if (partitionAttributes != null)
      partitionAttributesInfo = new PartitionAttributesInfo(partitionAttributes);

    if (evictionAttributes != null) {
      evictionAttributesInfo = new EvictionAttributesInfo(evictionAttributes);
    }
  }