This is an automated email from the ASF dual-hosted git repository. jinmeiliao pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/geode.git
commit e9f5cd35b64ffa63ca6ebddee8aba3ef91a76d4b Author: Aditya Anchuri <[email protected]> AuthorDate: Thu Nov 8 10:06:36 2018 -0800 GEODE-5971: Refactor CreateRegionCommand to extend SingleGfshCommand - Store config via generating a RegionConfig object rather than an XML entity Signed-off-by: Peter Tran <[email protected]> Signed-off-by: Aditya Anchuri <[email protected]> Signed-off-by: Jens Deppe <[email protected]> --- .gitignore | 1 + .../cli/commands/ConfigureEvictionThroughGfsh.java | 6 +- .../integrationTest/resources/assembly_content.txt | 2 +- geode-core/build.gradle | 1 - .../CreateDefinedIndexesCommandDUnitTest.java | 13 +- .../cli/commands/CreateRegionCommandDUnitTest.java | 120 +++- ...egionCommandPersistsConfigurationDUnitTest.java | 789 +++++++++++++++++++++ .../ImportOldClusterConfigDUnitTest.java | 2 +- .../java/org/apache/geode/cache/DataPolicy.java | 7 + .../org/apache/geode/cache/EvictionAttributes.java | 39 + .../org/apache/geode/cache/ExpirationAction.java | 15 + .../apache/geode/cache/ExpirationAttributes.java | 16 +- .../apache/geode/cache/PartitionAttributes.java | 19 + .../cache/configuration/RegionAttributesType.java | 11 + .../InternalConfigurationPersistenceService.java | 23 - .../apache/geode/internal/config/JAXBService.java | 4 +- .../internal/cli/commands/AlterRegionCommand.java | 3 +- .../internal/cli/commands/CreateRegionCommand.java | 123 +++- .../cli/domain/RegionAttributeGetFunction.java | 22 + .../cli/domain/RegionAttributeSetFunction.java | 22 + .../internal/cli/domain/RegionConfigFactory.java | 331 +++++++++ .../cli/functions/RegionAlterFunction.java | 12 +- .../cli/functions/RegionCreateFunction.java | 157 ++-- .../internal/cli/functions/RegionFunctionArgs.java | 86 ++- .../management/internal/cli/i18n/CliStrings.java | 2 + .../management/internal/cli/util/RegionPath.java | 16 + .../geode/redis/internal/RegionProvider.java | 20 +- .../cli/commands/CreateRegionCommandTest.java | 26 +- .../cli/domain/RegionConfigFactoryTest.java | 273 +++++++ .../cli/functions/RegionFunctionArgsTest.java | 45 +- .../cli/commands/CreateRegionCommandDUnitTest.java | 55 +- 31 files changed, 2061 insertions(+), 200 deletions(-) diff --git a/.gitignore b/.gitignore index 47d635b..1525f4a 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ out/ *.orig geode-pulse/screenshots/ /jpf.properties +geode-assembly/assembly_content.txt .git-together bin/ diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/ConfigureEvictionThroughGfsh.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/ConfigureEvictionThroughGfsh.java index 125d327..29ea9a5 100644 --- a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/ConfigureEvictionThroughGfsh.java +++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/ConfigureEvictionThroughGfsh.java @@ -57,7 +57,7 @@ public class ConfigureEvictionThroughGfsh { "create region --name=region6 --eviction-action=local-destroy --eviction-entry-count=1000 --type=REPLICATE_PERSISTENT") .expectFailure().execute(gfsh); assertThat(execution.getOutputText()).contains( - "ERROR: An Eviction Controller with local destroy eviction action is incompatible with"); + "An Eviction Controller with local destroy eviction action is incompatible with"); execution = GfshScript .of("connect --locator=localhost[10334]", "describe region --name=region1").execute(gfsh); @@ -112,7 +112,7 @@ public class ConfigureEvictionThroughGfsh { "create region --name=region6 --eviction-action=local-destroy --eviction-max-memory=1000 --type=REPLICATE_PERSISTENT") .expectFailure().execute(gfsh); assertThat(execution.getOutputText()).contains( - "ERROR: An Eviction Controller with local destroy eviction action is incompatible with"); + "An Eviction Controller with local destroy eviction action is incompatible with"); execution = GfshScript .of("connect --locator=localhost[10334]", "describe region --name=region1").execute(gfsh); @@ -181,7 +181,7 @@ public class ConfigureEvictionThroughGfsh { "create region --name=region6 --eviction-action=local-destroy --eviction-max-memory=1000 --eviction-object-sizer=MySizer --type=REPLICATE_PERSISTENT") .expectFailure().execute(gfsh); assertThat(execution.getOutputText()).contains( - "ERROR: An Eviction Controller with local destroy eviction action is incompatible with"); + "An Eviction Controller with local destroy eviction action is incompatible with"); execution = GfshScript .of("connect --locator=localhost[10334]", "describe region --name=region1").execute(gfsh); diff --git a/geode-assembly/src/integrationTest/resources/assembly_content.txt b/geode-assembly/src/integrationTest/resources/assembly_content.txt index 9cd4c19..f216ab3 100644 --- a/geode-assembly/src/integrationTest/resources/assembly_content.txt +++ b/geode-assembly/src/integrationTest/resources/assembly_content.txt @@ -957,4 +957,4 @@ tools/Modules/Apache_Geode_Modules-0.0.0-AppServer.zip tools/Modules/Apache_Geode_Modules-0.0.0-Tomcat.zip tools/Modules/Apache_Geode_Modules-0.0.0-tcServer.zip tools/Modules/Apache_Geode_Modules-0.0.0-tcServer30.zip -tools/Pulse/geode-pulse-0.0.0.war +tools/Pulse/geode-pulse-0.0.0.war \ No newline at end of file diff --git a/geode-core/build.gradle b/geode-core/build.gradle index 3f89a6f..668b2f1 100755 --- a/geode-core/build.gradle +++ b/geode-core/build.gradle @@ -15,7 +15,6 @@ * limitations under the License. */ - apply plugin: 'antlr' apply plugin: 'me.champeau.gradle.jmh' diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommandDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommandDUnitTest.java index 093a536..9b2df1b 100644 --- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommandDUnitTest.java +++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommandDUnitTest.java @@ -15,6 +15,7 @@ package org.apache.geode.management.internal.cli.commands; +import static org.apache.geode.management.internal.cli.result.model.ResultModel.MEMBER_STATUS_SECTION; import static org.assertj.core.api.Assertions.assertThat; import java.util.List; @@ -188,13 +189,15 @@ public class CreateDefinedIndexesCommandDUnitTest { CommandResult result = gfsh .executeCommand("create region --name=" + region1Name + " --type=REPLICATE --group=group1"); assertThat(result.getStatus()).isEqualTo(Result.Status.OK); - assertThat(result.getMapFromTableContent("0", "0").get("Member")).contains("server-1", + assertThat(result.getMapFromTableContent(MEMBER_STATUS_SECTION).get("Member")).contains( + "server-1", "server-2"); result = gfsh .executeCommand("create region --name=" + region2Name + " --type=REPLICATE --group=group1"); assertThat(result.getStatus()).isEqualTo(Result.Status.OK); - assertThat(result.getMapFromTableContent("0", "0").get("Member")).contains("server-1", + assertThat(result.getMapFromTableContent(MEMBER_STATUS_SECTION).get("Member")).contains( + "server-1", "server-2"); VMProvider.invokeInEveryMember(() -> { @@ -251,13 +254,15 @@ public class CreateDefinedIndexesCommandDUnitTest { CommandResult result = gfsh .executeCommand("create region --name=" + region1Name + " --type=REPLICATE --group=group1"); assertThat(result.getStatus()).isEqualTo(Result.Status.OK); - assertThat(result.getMapFromTableContent("0", "0").get("Member")).contains("server-1", + assertThat(result.getMapFromTableContent(MEMBER_STATUS_SECTION).get("Member")).contains( + "server-1", "server-2"); result = gfsh .executeCommand("create region --name=" + region2Name + " --type=REPLICATE --group=group2"); assertThat(result.getStatus()).isEqualTo(Result.Status.OK); - assertThat(result.getMapFromTableContent("0", "0").get("Member")).contains("server-3"); + assertThat(result.getMapFromTableContent(MEMBER_STATUS_SECTION).get("Member")) + .contains("server-3"); gfsh.executeAndAssertThat( "define index --name=" + index1Name + " --expression=value1 --region=" + region1Name) diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java index 8d8dc19..0c50623 100644 --- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java +++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java @@ -20,10 +20,12 @@ import static org.assertj.core.api.Assertions.assertThat; import java.io.File; import java.io.Serializable; import java.util.Arrays; +import java.util.List; import java.util.stream.Collectors; import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -31,13 +33,19 @@ import org.junit.rules.TemporaryFolder; import org.junit.rules.TestName; import org.apache.geode.cache.Cache; +import org.apache.geode.cache.Declarable; +import org.apache.geode.cache.EntryOperation; import org.apache.geode.cache.PartitionResolver; import org.apache.geode.cache.Region; +import org.apache.geode.cache.asyncqueue.AsyncEvent; +import org.apache.geode.cache.asyncqueue.AsyncEventListener; import org.apache.geode.cache.configuration.CacheConfig; import org.apache.geode.cache.configuration.CacheElement; import org.apache.geode.cache.configuration.RegionConfig; import org.apache.geode.cache.util.CacheListenerAdapter; +import org.apache.geode.compression.Compressor; import org.apache.geode.compression.SnappyCompressor; +import org.apache.geode.internal.cache.InternalRegion; import org.apache.geode.internal.cache.PartitionedRegion; import org.apache.geode.internal.cache.RegionEntryContext; import org.apache.geode.test.compiler.JarBuilder; @@ -59,6 +67,37 @@ public class CreateRegionCommandDUnitTest { implements Serializable { } + public static class DummyAEQListener implements AsyncEventListener, Declarable { + @Override + public boolean processEvents(List<AsyncEvent> events) { + return false; + } + } + + public static class DummyPartitionResolver implements PartitionResolver, Declarable { + @Override + public Object getRoutingObject(EntryOperation opDetails) { + return null; + } + + @Override + public String getName() { + return "dummy"; + } + } + + public static class DummyCompressor implements Compressor, Declarable { + @Override + public byte[] compress(byte[] input) { + return new byte[0]; + } + + @Override + public byte[] decompress(byte[] input) { + return new byte[0]; + } + } + @ClassRule public static ClusterStartupRule lsRule = new ClusterStartupRule(); @@ -230,6 +269,7 @@ public class CreateRegionCommandDUnitTest { gfsh.executeAndAssertThat("destroy region --name=/TEMPLATE").statusIsSuccess(); } + @Test public void cannotSetRegionExpirationForPartitionedTemplate() { gfsh.executeAndAssertThat("create region --name=/TEMPLATE --type=PARTITION") @@ -431,11 +471,12 @@ public class CreateRegionCommandDUnitTest { } @Test - public void startWithReplicateProxyThenPartitionRegion() { + public void startWithReplicateProxyThenPartitionRegion() throws Exception { String regionName = testName.getMethodName(); gfsh.executeAndAssertThat( "create region --type=REPLICATE_PROXY --group=group1 --name=" + regionName) .statusIsSuccess().tableHasRowWithValues("Member", "server-1"); + gfsh.executeAndAssertThat("create region --type=PARTITION --group=group2 --name=" + regionName) .statusIsError().containsOutput("The existing region is not a partitioned region"); gfsh.executeAndAssertThat( @@ -560,6 +601,83 @@ public class CreateRegionCommandDUnitTest { .containsOutput("Region /startWithLocalRegion already exists on the cluster"); } + @Test + public void cannotDisableCloningWhenCompressorIsSet() { + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=REPLICATE" + + " --compressor=" + DummyCompressor.class.getName() + + " --enable-cloning=false").statusIsError(); + } + + /** + * Ignored this test until we refactor the FetchRegionAttributesFunction to not use + * AttributesFactory, and instead use RegionConfig, which we will do as part of implementing + * GEODE-6103 + */ + @Ignore + @Test + public void testCreateRegionFromTemplateWithAsyncEventListeners() { + String queueId = "queue1"; + gfsh.executeAndAssertThat( + "create async-event-queue --id=" + queueId + + " --listener=" + CreateRegionCommandDUnitTest.DummyAEQListener.class.getName()) + .statusIsSuccess(); + + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat( + "create region --name=" + regionName + + " --type=REPLICATE" + + " --async-event-queue-id=" + queueId) + .statusIsSuccess(); + + gfsh.executeAndAssertThat( + "create region --name=" + regionName + "-from-template" + + " --template-region=" + regionName) + .statusIsSuccess(); + + server1.invoke(() -> { + Region regionFromTemplate = ClusterStartupRule.getCache() + .getRegion(regionName + "-from-template"); + assertThat(regionFromTemplate).isNotNull(); + assertThat(((InternalRegion) regionFromTemplate).getAsyncEventQueueIds()) + .contains(queueId); + }); + } + + /** + * Ignored this test until we refactor the FetchRegionAttributesFunction to not use + * AttributesFactory, and instead use RegionConfig, which we will do as part of implementing + * GEODE-6103 + */ + @Ignore + @Test + public void testCreateRegionFromTemplateWithPartitionResolver() { + String regionName = testName.getMethodName(); + String regionFromTemplateName = regionName + "-from-template"; + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=PARTITION" + + " --partition-resolver=" + DummyPartitionResolver.class.getName()).statusIsSuccess(); + gfsh.executeAndAssertThat("create region" + + " --name=" + regionFromTemplateName + + " --template-region=" + regionName).statusIsSuccess(); + + server1.invoke(() -> { + Region regionFromTemplate = ClusterStartupRule.getCache() + .getRegion(regionName + "-from-template"); + assertThat(regionFromTemplate).isNotNull(); + assertThat(((InternalRegion) regionFromTemplate).getPartitionAttributes() + .getPartitionResolver()) + .isNotNull(); + assertThat(((InternalRegion) regionFromTemplate).getPartitionAttributes() + .getPartitionResolver().getName()) + .isEqualTo(DummyPartitionResolver.class.getName()); + }); + } + private String getUniversalClassCode(String classname) { String code = "package io.pivotal;" + "import org.apache.geode.cache.CacheLoader;" + "import org.apache.geode.cache.CacheLoaderException;" diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java new file mode 100644 index 0000000..275fac9 --- /dev/null +++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java @@ -0,0 +1,789 @@ +/* + * 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.commands; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TestName; + +import org.apache.geode.cache.CacheLoader; +import org.apache.geode.cache.CacheLoaderException; +import org.apache.geode.cache.CustomExpiry; +import org.apache.geode.cache.Declarable; +import org.apache.geode.cache.EntryOperation; +import org.apache.geode.cache.ExpirationAttributes; +import org.apache.geode.cache.LoaderHelper; +import org.apache.geode.cache.PartitionResolver; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.configuration.CacheConfig; +import org.apache.geode.cache.configuration.CacheElement; +import org.apache.geode.cache.configuration.ExpirationAttributesType; +import org.apache.geode.cache.configuration.RegionAttributesDataPolicy; +import org.apache.geode.cache.configuration.RegionAttributesType; +import org.apache.geode.cache.configuration.RegionConfig; +import org.apache.geode.cache.util.CacheListenerAdapter; +import org.apache.geode.cache.util.CacheWriterAdapter; +import org.apache.geode.compression.Compressor; +import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService; +import org.apache.geode.test.dunit.rules.ClusterStartupRule; +import org.apache.geode.test.dunit.rules.MemberVM; +import org.apache.geode.test.junit.categories.RegionsTest; +import org.apache.geode.test.junit.rules.GfshCommandRule; +import org.apache.geode.test.junit.rules.serializable.SerializableTestName; + +@Category({RegionsTest.class}) +public class CreateRegionCommandPersistsConfigurationDUnitTest { + + private MemberVM locator, server1; + + @Rule + public ClusterStartupRule clusterRule = new ClusterStartupRule(); + + @Rule + public GfshCommandRule gfsh = new GfshCommandRule(); + + @Rule + public TestName testName = new SerializableTestName(); + + public static class DummyCacheListener extends CacheListenerAdapter { + } + + public static class DummyCustomExpiry implements CustomExpiry, Declarable { + @Override + public ExpirationAttributes getExpiry(Region.Entry entry) { + return null; + } + } + + public static class DummyPartitionResolver implements PartitionResolver, Declarable { + @Override + public Object getRoutingObject(EntryOperation opDetails) { + return null; + } + + @Override + public String getName() { + return "dummy"; + } + } + + public static class DummyCompressor implements Compressor, Declarable { + @Override + public byte[] compress(byte[] input) { + return new byte[0]; + } + + @Override + public byte[] decompress(byte[] input) { + return new byte[0]; + } + } + + public static class DummyCacheLoader implements CacheLoader, Declarable { + @Override + public Object load(LoaderHelper helper) throws CacheLoaderException { + return null; + } + } + + public static class DummyCacheWriter extends CacheWriterAdapter { + } + + @Before + public void before() throws Exception { + locator = clusterRule.startLocatorVM(0); + server1 = clusterRule.startServerVM(1, locator.getPort()); + + gfsh.connectAndVerify(locator); + } + + @Test + public void createRegionPersistsEmptyConfig() { + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=REPLICATE") + .statusIsSuccess(); + + server1.stop(); + server1 = clusterRule.startServerVM(1, "group1", locator.getPort()); + + gfsh.executeAndAssertThat("list regions") + .statusIsSuccess().containsOutput(regionName); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + RegionConfig regionConfig = regions.get(0); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(regionName); + assertThat(regionConfig.getIndexes()).isEmpty(); + assertThat(regionConfig.getRegions()).isEmpty(); + assertThat(regionConfig.getEntries()).isEmpty(); + assertThat(regionConfig.getCustomRegionElements()).isEmpty(); + }); + } + + @Test + public void createRegionPersistsConfigParams() { + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=PARTITION" + + " --enable-statistics=true" + " --enable-async-conflation=true" + + " --entry-idle-time-expiration=100").statusIsSuccess(); + + server1.stop(); + server1 = clusterRule.startServerVM(1, "group1", locator.getPort()); + + gfsh.executeAndAssertThat("list regions") + .statusIsSuccess().containsOutput(regionName); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + RegionConfig regionConfig = regions.get(0); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(regionName); + assertThat(regionConfig.getRegionAttributes()).hasSize(1); + + RegionAttributesType attr = regionConfig.getRegionAttributes().get(0); + assertThat(attr.isStatisticsEnabled()).isTrue(); + assertThat(attr.isEnableAsyncConflation()).isTrue(); + + ExpirationAttributesType entryIdleTimeExp = attr.getEntryIdleTime().getExpirationAttributes(); + assertThat(entryIdleTimeExp.getTimeout()).isEqualTo("100"); + }); + + server1.invoke(() -> { + Region<?, ?> region = ClusterStartupRule.getCache().getRegion(regionName); + assertThat(region.getAttributes().getStatisticsEnabled()) + .describedAs("Expecting statistics to be enabled") + .isTrue(); + assertThat(region.getAttributes().getEnableAsyncConflation()) + .describedAs("Expecting async conflation to be enabled") + .isTrue(); + assertThat(region.getAttributes().getEntryIdleTimeout().getTimeout()) + .describedAs("Expecting entry idle time exp timeout to be 100") + .isEqualTo(100); + }); + } + + @Test + public void createRegionFromTemplateCreatesCorrectConfig() { + String regionName = testName.getMethodName(); + String templateRegionName = regionName + "_template"; + gfsh.executeAndAssertThat("create region" + + " --name=" + templateRegionName + + " --type=PARTITION" + + " --cache-listener=" + DummyCacheListener.class.getName() + + " --enable-statistics=true" + + " --enable-async-conflation=true" + + " --entry-idle-time-expiration=100").statusIsSuccess(); + + gfsh.executeAndAssertThat( + "create region --name=" + regionName + " --template-region=" + templateRegionName); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName); + + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(regionName); + assertThat(regionConfig.getRegionAttributes()).hasSize(1); + + RegionAttributesType attr = regionConfig.getRegionAttributes().get(0); + assertThat(attr.isStatisticsEnabled()).isTrue(); + assertThat(attr.isEnableAsyncConflation()).isTrue(); + + ExpirationAttributesType entryIdleTimeExp = attr.getEntryIdleTime().getExpirationAttributes(); + assertThat(entryIdleTimeExp.getTimeout()).isEqualTo("100"); + }); + } + + @Test + public void createRegionAndValidateAllConfigIsPersistedForReplicatedRegion() { + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=REPLICATE" + + " --cache-listener=" + DummyCacheListener.class.getName() + + " --cache-loader=" + DummyCacheLoader.class.getName() + + " --cache-writer=" + DummyCacheWriter.class.getName() + + " --compressor=" + DummyCompressor.class.getName() + + " --enable-async-conflation=false" + + " --enable-concurrency-checks=false" + + " --enable-multicast=false" + + " --concurrency-level=1" + + " --enable-statistics=true" + + " --enable-subscription-conflation=true" + + " --entry-idle-time-expiration=100" + + " --entry-idle-time-expiration-action=local-destroy" + + " --entry-time-to-live-expiration=200" + + " --entry-time-to-live-expiration-action=local-destroy" + + " --eviction-action=local-destroy" + + " --key-constraint=" + Object.class.getName() + + " --off-heap=false" + + " --region-idle-time-expiration=100" + + " --region-idle-time-expiration-action=local-destroy" + + " --region-time-to-live-expiration=200" + + " --region-time-to-live-expiration-action=local-destroy" + + " --value-constraint=" + Object.class.getName()).statusIsSuccess(); + + String regionNameFromTemplate = regionName + "-from-template"; + gfsh.executeAndAssertThat("create region --name=" + regionNameFromTemplate + + " --template-region=" + regionName) + .statusIsSuccess(); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(2); + + List<String> regionNames = Arrays.asList(regionName, regionNameFromTemplate); + regionNames.forEach(name -> { + RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(name); + assertThat(regionConfig.getRegionAttributes()) + .describedAs("Expecting region attributes to exist") + .hasSize(1); + + RegionAttributesType attr = regionConfig.getRegionAttributes().get(0); + assertThat(attr.getCacheListeners().get(0).toString()) + .describedAs("Expecting one cache listener for region " + name) + .isEqualTo(DummyCacheListener.class.getName()); + assertThat(attr.getCacheLoader().toString()) + .describedAs("Expecting a DummyCacheLoader for region " + name) + .isEqualTo(DummyCacheLoader.class.getName()); + assertThat(attr.getCacheWriter().toString()) + .describedAs("Expecting a DummyCacheWriter for region " + name) + .isEqualTo(DummyCacheWriter.class.getName()); + assertThat(attr.getCompressor().toString()) + .describedAs("Expecting a DummyCompressor for region " + name) + .isEqualTo(DummyCompressor.class.getName()); + assertThat(attr.isEnableAsyncConflation()) + .describedAs("Expecting async conflation to not be enabled for region " + + name) + .isFalse(); + assertThat(attr.isConcurrencyChecksEnabled()) + .describedAs("Expecting concurrency checks not to be enabled for region " + + name) + .isFalse(); + assertThat(attr.isMulticastEnabled()) + .describedAs("Expecting multicast is not enabled for region " + name) + .isFalse(); + assertThat(attr.getConcurrencyLevel()) + .describedAs("Expecting concurrency level to be 1 for region " + name) + .isEqualTo("1"); + assertThat(attr.isStatisticsEnabled()) + .describedAs("Expecting statistics to be enabled for region " + name) + .isTrue(); + assertThat(attr.isCloningEnabled()) + .describedAs("Expecting cloning to be enabled for region " + name + + " since compressor is provided") + .isTrue(); + assertThat(attr.isEnableSubscriptionConflation()) + .describedAs("Expecting subscription conflation to be enabled for region " + + name) + .isTrue(); + assertThat(attr.getEntryIdleTime().getExpirationAttributes().getTimeout()) + .describedAs("Entry idle time timeout should be 100 for region " + name) + .isEqualTo("100"); + assertThat(attr.getEntryIdleTime().getExpirationAttributes().getAction()) + .describedAs("Entry idle time expiration action should be local-destroy for region " + + name) + .isEqualTo("local-destroy"); + assertThat(attr.getEntryTimeToLive().getExpirationAttributes().getTimeout()) + .describedAs("Expecting entry time to live expiration to be 200 for region " + + name) + .isEqualTo("200"); + assertThat(attr.getEntryTimeToLive().getExpirationAttributes().getAction()) + .describedAs("Entry time to live expiration action should be local-destroy " + + "for region " + name) + .isEqualTo("local-destroy"); + assertThat(attr.getEvictionAttributes().getLruHeapPercentage().getAction().value()) + .describedAs("Eviction action should be local-destroy for region " + name) + .isEqualTo("local-destroy"); + assertThat(attr.getKeyConstraint()) + .describedAs("Expected key constraint to be " + Object.class.getName() + + " for region " + name) + .isEqualTo(Object.class.getName()); + assertThat(attr.isOffHeap()) + .describedAs("Expected off heap to be false for region " + name) + .isFalse(); + assertThat(attr.getRegionIdleTime().getExpirationAttributes().getTimeout()) + .describedAs("Expecting region idle time expiration to be 100 for region " + + name) + .isEqualTo("100"); + assertThat(attr.getRegionIdleTime().getExpirationAttributes().getAction()) + .describedAs("Expecting region idle time expiration action to be " + + "local-destroy for region " + name) + .isEqualTo("local-destroy"); + assertThat(attr.getRegionTimeToLive().getExpirationAttributes().getTimeout()) + .describedAs("Expecting region idle time timeout to be 200 for " + + "region " + name) + .isEqualTo("200"); + assertThat(attr.getRegionTimeToLive().getExpirationAttributes().getAction()) + .describedAs("Expecting region ttl action to be local-destroy for " + + "region " + name) + .isEqualTo("local-destroy"); + assertThat(attr.getValueConstraint()) + .describedAs("Expecting value constraint to be Object.class for " + + "region " + name) + .isEqualTo(Object.class.getName()); + }); + }); + } + + @Test + public void createRegionDoesNotPersistEmptyOrDefaultEvictionAttributes() { + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=REPLICATE").statusIsSuccess(); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(1); + + List<String> regionNames = Arrays.asList(regionName); + regionNames.forEach(name -> { + RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(name); + assertThat(regionConfig.getRegionAttributes()) + .describedAs("Expecting region attributes to exist") + .hasSize(1); + + RegionAttributesType attr = regionConfig.getRegionAttributes().get(0); + assertThat(attr.getEvictionAttributes()) + .describedAs("Eviction attributes should be null for " + name) + .isNull(); + }); + }); + } + + @Test + public void createRegionPersistsAEQConfig() { + String queueId = "queue1"; + gfsh.executeAndAssertThat( + "create async-event-queue --id=" + queueId + + " --listener=" + CreateRegionCommandDUnitTest.DummyAEQListener.class.getName()) + .statusIsSuccess(); + + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat( + "create region --name=" + regionName + + " --type=REPLICATE" + + " --async-event-queue-id=" + queueId) + .statusIsSuccess(); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(1); + RegionConfig regionConfig = CacheElement.findElement(regions, regionName); + assertThat(regionConfig.getRegionAttributes().get(0).getAsyncEventQueueIds()) + .contains(queueId); + }); + } + + @Test + public void createRegionWithColocation() { + String regionName = testName.getMethodName(); + String colocatedRegionName = regionName + "-colocated"; + String colocatedRegionFromTemplateName = colocatedRegionName + "-from-template"; + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=PARTITION"); + gfsh.executeAndAssertThat("create region" + + " --name=" + colocatedRegionName + + " --colocated-with=" + regionName + + " --type=PARTITION"); + + gfsh.executeAndAssertThat("create region" + + " --name=" + colocatedRegionFromTemplateName + + " --template-region=" + colocatedRegionName); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(3); + + RegionConfig colocatedConfig = CacheElement.findElement(regions, colocatedRegionName); + assertThat( + colocatedConfig.getRegionAttributes().get(0).getPartitionAttributes().getColocatedWith()) + .isEqualTo("/" + regionName); + + RegionConfig colocatedConfigFromTemplate = CacheElement.findElement(regions, + colocatedRegionFromTemplateName); + assertThat( + colocatedConfigFromTemplate.getRegionAttributes().get(0).getPartitionAttributes() + .getColocatedWith()) + .isEqualTo("/" + regionName); + }); + } + + @Test + public void createRegionPersistsDiskstores() throws Exception { + String regionName = testName.getMethodName(); + String store = "Store1"; + gfsh.executeAndAssertThat("create disk-store" + + " --name=" + store + + " --dir=/tmp/foo").statusIsSuccess(); + + // Give disk store time to get created + Thread.sleep(2000); + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=REPLICATE_PERSISTENT" + + " --disk-store=" + store + + " --enable-synchronous-disk=true").statusIsSuccess(); + + String regionNameFromTemplate = regionName + "-from-template"; + gfsh.executeAndAssertThat("create region --name=" + regionNameFromTemplate + + " --template-region=" + regionName) + .statusIsSuccess(); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(2); + + List<String> regionNames = Arrays.asList(regionName, regionNameFromTemplate); + regionNames.forEach(name -> { + RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(name); + + RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().get(0); + assertThat(regionAttributes.getDiskStoreName()) + .isEqualTo(store); + assertThat(regionAttributes.isDiskSynchronous()) + .isTrue(); + }); + }); + } + + @Test + public void createRegionPersistsPartitionAttributes() { + String regionName = testName.getMethodName(); + String regionFromTemplateName = regionName + "-from-template"; + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=PARTITION" + + " --recovery-delay=1" + + " --local-max-memory=1000" + + " --redundant-copies=1" + + " --startup-recovery-delay=1" + + " --total-max-memory=100" + + " --total-num-buckets=1").statusIsSuccess(); + gfsh.executeAndAssertThat("create region" + + " --name=" + regionFromTemplateName + + " --template-region=" + regionName); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(2); + + List<String> regionNames = Arrays.asList(regionName, regionFromTemplateName); + regionNames.forEach(name -> { + RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(name); + + RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().get(0); + RegionAttributesType.PartitionAttributes partitionAttributes = + regionAttributes.getPartitionAttributes(); + + assertThat(partitionAttributes.getRecoveryDelay()) + .describedAs("Recovery delay should be 1 for region " + name) + .isEqualTo("1"); + assertThat(partitionAttributes.getLocalMaxMemory()) + .describedAs("Local max memory should be 1000 for region " + name) + .isEqualTo("1000"); + assertThat(partitionAttributes.getRedundantCopies()) + .describedAs("Redundant copies should be 1 for region " + name) + .isEqualTo("1"); + assertThat(partitionAttributes.getStartupRecoveryDelay()) + .describedAs("Startup recovery delay should be 1 for region " + name) + .isEqualTo("1"); + assertThat(partitionAttributes.getTotalMaxMemory()) + .describedAs("Total max memory should be 100 for region " + name) + .isEqualTo("100"); + assertThat(partitionAttributes.getTotalNumBuckets()) + .describedAs("Total num buckets should be 1 for region " + name) + .isEqualTo("1"); + }); + }); + } + + @Test + public void createRegionPersistsPartitionResolver() { + String regionName = testName.getMethodName(); + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=PARTITION" + + " --partition-resolver=" + DummyPartitionResolver.class.getName()).statusIsSuccess(); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(1); + + RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(regionName); + + RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().get(0); + RegionAttributesType.PartitionAttributes partitionAttributes = + regionAttributes.getPartitionAttributes(); + + assertThat(partitionAttributes.getPartitionResolver().getClassName()) + .isEqualTo(DummyPartitionResolver.class.getName()); + }); + } + + @Test + public void createRegionDoesNotPersistEmptyOrDefaultPartitionAttributes() { + String regionName = testName.getMethodName(); + String regionFromTemplateName = regionName + "-from-template"; + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=REPLICATE").statusIsSuccess(); + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionFromTemplateName + + " --template-region=" + regionName); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(2); + + RegionConfig regionConfig = + CacheElement.findElement(config.getRegions(), regionFromTemplateName); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(regionFromTemplateName); + assertThat(regionConfig.getRegionAttributes()) + .describedAs("Expecting region attributes to exist") + .hasSize(1); + + RegionAttributesType attr = regionConfig.getRegionAttributes().get(0); + assertThat(attr.getPartitionAttributes()) + .describedAs("Partition attributes should be null for " + regionFromTemplateName) + .isNull(); + }); + } + + @Test + public void createRegionDoestNotPersistEmptyOrDefaultExpirationAttributes() { + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=REPLICATE").statusIsSuccess(); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(1); + + RegionConfig regionConfig = + CacheElement.findElement(config.getRegions(), regionName); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(regionName); + assertThat(regionConfig.getRegionAttributes()) + .describedAs("Expecting region attributes to exist") + .hasSize(1); + + RegionAttributesType attr = regionConfig.getRegionAttributes().get(0); + assertThat(attr.getRegionTimeToLive()) + .describedAs("Expiration attributes should be null for " + regionName) + .isNull(); + assertThat(attr.getRegionIdleTime()) + .describedAs("Expiration attributes should be null for " + regionName) + .isNull(); + assertThat(attr.getEntryIdleTime()) + .describedAs("Expiration attributes should be null for " + regionName) + .isNull(); + assertThat(attr.getEntryTimeToLive()) + .describedAs("Expiration attributes should be null for " + regionName) + .isNull(); + }); + } + + @Test + public void createRegionPersistsDisableCloningSetting() { + String regionName = testName.getMethodName(); + String regionFromTemplateName = regionName + "-from-template"; + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=REPLICATE" + + " --enable-cloning=false").statusIsSuccess(); + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionFromTemplateName + + " --template-region=" + regionName); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(2); + + List<String> regionNames = Arrays.asList(regionName, regionFromTemplateName); + regionNames.forEach(name -> { + RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(name); + assertThat(regionConfig.getRegionAttributes()) + .describedAs("Expecting region attributes to exist for " + name) + .hasSize(1); + + RegionAttributesType attr = regionConfig.getRegionAttributes().get(0); + assertThat(attr.isCloningEnabled()) + .describedAs("Cloning should be disabled for " + name) + .isFalse(); + }); + }); + } + + @Test + public void createRegionPersistsCustomExpiryClass() { + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=REPLICATE" + + " --enable-statistics=true" + + " --entry-idle-time-custom-expiry=" + DummyCustomExpiry.class.getName()) + .statusIsSuccess(); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(1); + + RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(regionName); + assertThat(regionConfig.getRegionAttributes()) + .describedAs("Expecting region attributes to exist for " + regionName) + .hasSize(1); + RegionAttributesType attr = regionConfig.getRegionAttributes().get(0); + assertThat(attr.getEntryIdleTime().getExpirationAttributes().getCustomExpiry().toString()) + .describedAs("Entry expiration custom expiration should be DummyCustomExpiry") + .isEqualTo(DummyCustomExpiry.class.getName()); + }); + } + + @Test + public void createRegionPersistsImplicitTemplateAttributes() { + String regionName = testName.getMethodName(); + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=PARTITION") + .statusIsSuccess(); + + locator.invoke(() -> { + InternalConfigurationPersistenceService cc = + ClusterStartupRule.getLocator().getConfigurationPersistenceService(); + CacheConfig config = cc.getCacheConfig("cluster"); + + List<RegionConfig> regions = config.getRegions(); + assertThat(regions).isNotEmpty(); + assertThat(regions).hasSize(1); + + RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName); + assertThat(regionConfig).isNotNull(); + assertThat(regionConfig.getName()).isEqualTo(regionName); + assertThat(regionConfig.getRegionAttributes()) + .describedAs("Expecting region attributes to exist for " + regionName) + .hasSize(1); + + RegionAttributesType attr = regionConfig.getRegionAttributes().get(0); + assertThat(attr.getDataPolicy()) + .describedAs("Data policy for partitioned region should be persisted correctly") + .isEqualTo(RegionAttributesDataPolicy.PARTITION); + }); + } +} diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/configuration/ImportOldClusterConfigDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/configuration/ImportOldClusterConfigDUnitTest.java index 287ed83..e6974a2 100644 --- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/configuration/ImportOldClusterConfigDUnitTest.java +++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/configuration/ImportOldClusterConfigDUnitTest.java @@ -62,7 +62,7 @@ public class ImportOldClusterConfigDUnitTest { } @Test - public void importOldConfigThenCreateRegionCorruptsCachXml() throws Exception { + public void importOldConfigThenCreateRegionCorruptsCacheXml() throws Exception { locator = lsRule.startLocatorVM(0); gfsh.connectAndVerify(locator); diff --git a/geode-core/src/main/java/org/apache/geode/cache/DataPolicy.java b/geode-core/src/main/java/org/apache/geode/cache/DataPolicy.java index 5ba6e53..06221fd 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/DataPolicy.java +++ b/geode-core/src/main/java/org/apache/geode/cache/DataPolicy.java @@ -18,6 +18,8 @@ package org.apache.geode.cache; import java.io.ObjectStreamException; +import org.apache.geode.cache.configuration.RegionAttributesDataPolicy; + /** * Enumerated type for region data policy. The data policy specifies how this local cache will @@ -289,4 +291,9 @@ public class DataPolicy implements java.io.Serializable { public String toString() { return this.name; } + + public RegionAttributesDataPolicy toConfigType() { + String configName = this.name.toLowerCase().replace("_", "-"); + return RegionAttributesDataPolicy.fromValue(configName); + } } diff --git a/geode-core/src/main/java/org/apache/geode/cache/EvictionAttributes.java b/geode-core/src/main/java/org/apache/geode/cache/EvictionAttributes.java index 66a1bb7..b333b2e 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/EvictionAttributes.java +++ b/geode-core/src/main/java/org/apache/geode/cache/EvictionAttributes.java @@ -16,6 +16,8 @@ package org.apache.geode.cache; import org.apache.geode.DataSerializable; +import org.apache.geode.cache.configuration.EnumActionDestroyOverflow; +import org.apache.geode.cache.configuration.RegionAttributesType; import org.apache.geode.cache.control.ResourceManager; import org.apache.geode.cache.util.ObjectSizer; import org.apache.geode.internal.cache.EvictionAttributesImpl; @@ -505,4 +507,41 @@ public abstract class EvictionAttributes implements DataSerializable { .setAction(evictionAction).setMaximum(maximumMegabytes).setObjectSizer(null); } + public RegionAttributesType.EvictionAttributes convertToConfigEvictionAttributes() { + RegionAttributesType.EvictionAttributes configAttributes = + new RegionAttributesType.EvictionAttributes(); + EnumActionDestroyOverflow action = EnumActionDestroyOverflow.fromValue(this.getAction() + .toString()); + EvictionAlgorithm algorithm = getAlgorithm(); + String objectSizerClass = getObjectSizer().getClass().toString(); + Integer maximum = getMaximum(); + + if (algorithm.isLRUHeap()) { + RegionAttributesType.EvictionAttributes.LruHeapPercentage heapPercentage = + new RegionAttributesType.EvictionAttributes.LruHeapPercentage(); + heapPercentage.setAction(action); + heapPercentage.setClassName(objectSizerClass); + configAttributes.setLruHeapPercentage(heapPercentage); + } else if (algorithm.isLRUMemory()) { + RegionAttributesType.EvictionAttributes.LruMemorySize memorySize = + new RegionAttributesType.EvictionAttributes.LruMemorySize(); + memorySize.setAction(action); + memorySize.setClassName(objectSizerClass); + memorySize.setMaximum(maximum.toString()); + configAttributes.setLruMemorySize(memorySize); + } else { + RegionAttributesType.EvictionAttributes.LruEntryCount entryCount = + new RegionAttributesType.EvictionAttributes.LruEntryCount(); + entryCount.setAction(action); + entryCount.setMaximum(maximum.toString()); + configAttributes.setLruEntryCount(entryCount); + } + + return configAttributes; + } + + public boolean isEmpty() { + return getAction() == EvictionAction.NONE && getAlgorithm() == EvictionAlgorithm.NONE; + } + } diff --git a/geode-core/src/main/java/org/apache/geode/cache/ExpirationAction.java b/geode-core/src/main/java/org/apache/geode/cache/ExpirationAction.java index ea7df84..0b66ddc 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/ExpirationAction.java +++ b/geode-core/src/main/java/org/apache/geode/cache/ExpirationAction.java @@ -120,6 +120,21 @@ public class ExpirationAction implements Serializable { return this.name; } + public String toXmlString() { + switch (this.name) { + case "INVALIDATE": + return "invalidate"; + case "DESTROY": + return "destroy"; + case "LOCAL_DESTROY": + return "local-destroy"; + case "LOCAL_INVALIDATE": + return "local-invalidate"; + default: + return null; + } + } + // The 4 declarations below are necessary for serialization private static int nextOrdinal = 0; public final int ordinal = nextOrdinal++; diff --git a/geode-core/src/main/java/org/apache/geode/cache/ExpirationAttributes.java b/geode-core/src/main/java/org/apache/geode/cache/ExpirationAttributes.java index 8cf2fb0..ebd08ee 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/ExpirationAttributes.java +++ b/geode-core/src/main/java/org/apache/geode/cache/ExpirationAttributes.java @@ -21,6 +21,7 @@ import java.io.IOException; import org.apache.geode.DataSerializable; import org.apache.geode.DataSerializer; +import org.apache.geode.cache.configuration.ExpirationAttributesType; import org.apache.geode.internal.InternalDataSerializer; /** @@ -149,7 +150,7 @@ public class ExpirationAttributes implements DataSerializable { public void fromData(DataInput in) throws IOException, ClassNotFoundException { this.timeout = in.readInt(); - this.action = (ExpirationAction) DataSerializer.readObject(in); + this.action = DataSerializer.readObject(in); } @@ -157,4 +158,17 @@ public class ExpirationAttributes implements DataSerializable { out.writeInt(this.timeout); DataSerializer.writeObject(this.action, out); } + + public ExpirationAttributesType toConfigType() { + ExpirationAttributesType t = new ExpirationAttributesType(); + t.setTimeout(Integer.toString(this.timeout)); + t.setAction(this.action.toXmlString()); + + return t; + } + + public boolean isDefault() { + return (this.action == null || this.action == ExpirationAction.INVALIDATE) + && (this.timeout == 0); + } } diff --git a/geode-core/src/main/java/org/apache/geode/cache/PartitionAttributes.java b/geode-core/src/main/java/org/apache/geode/cache/PartitionAttributes.java index d137fa3..2cab775 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/PartitionAttributes.java +++ b/geode-core/src/main/java/org/apache/geode/cache/PartitionAttributes.java @@ -18,6 +18,8 @@ package org.apache.geode.cache; import java.util.List; import java.util.Properties; +import org.apache.geode.cache.configuration.DeclarableType; +import org.apache.geode.cache.configuration.RegionAttributesType; import org.apache.geode.cache.partition.PartitionListener; /** @@ -153,4 +155,21 @@ public interface PartitionAttributes<K, V> { */ List<FixedPartitionAttributes> getFixedPartitionAttributes(); + default RegionAttributesType.PartitionAttributes convertToConfigPartitionAttributes() { + RegionAttributesType.PartitionAttributes configAttributes = + new RegionAttributesType.PartitionAttributes(); + configAttributes.setColocatedWith(getColocatedWith()); + configAttributes.setLocalMaxMemory(Integer.toString(getLocalMaxMemory())); + if (getPartitionResolver() != null) { + configAttributes.setPartitionResolver(new DeclarableType(getPartitionResolver().getName())); + } + configAttributes.setRecoveryDelay(Long.toString(getRecoveryDelay())); + configAttributes.setStartupRecoveryDelay(Long.toString(getStartupRecoveryDelay())); + configAttributes.setRedundantCopies(Integer.toString(getRedundantCopies())); + configAttributes.setTotalMaxMemory(Long.toString(getTotalMaxMemory())); + configAttributes.setTotalNumBuckets(Long.toString(getTotalNumBuckets())); + + return configAttributes; + } + } diff --git a/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionAttributesType.java b/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionAttributesType.java index e579879..436bd36 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionAttributesType.java +++ b/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionAttributesType.java @@ -1795,6 +1795,17 @@ public class RegionAttributesType { @XmlElement(name = "lru-memory-size", namespace = "http://geode.apache.org/schema/cache") protected RegionAttributesType.EvictionAttributes.LruMemorySize lruMemorySize; + public String toStringRep() { + return "lru-entry-count: " + + this.lruEntryCount.getMaximum() + ", " + + this.lruEntryCount.getAction().toString() + ", " + + "\nlru-heap-percentage: " + + this.lruHeapPercentage.getAction().toString() + + "\nlru-memory-size: " + + this.lruMemorySize.getMaximum() + + this.lruMemorySize.getAction().toString(); + } + /** * Gets the value of the lruEntryCount property. * diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java index 74aba94..c86a969 100644 --- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java +++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java @@ -226,29 +226,6 @@ public class InternalConfigurationPersistenceService implements ConfigurationPer } /** - * Finds xml element in a group's xml, with the tagName that has given attribute and value - */ - public Element getXmlElement(String group, String tagName, String attribute, String value) - throws IOException, SAXException, ParserConfigurationException { - if (group == null) { - group = "cluster"; - } - Configuration config = getConfiguration(group); - Document document = XmlUtils.createDocumentFromXml(config.getCacheXmlContent()); - NodeList elements = document.getElementsByTagName(tagName); - if (elements == null || elements.getLength() == 0) { - return null; - } else { - for (int i = 0; i < elements.getLength(); i++) { - Element eachElement = (Element) elements.item(i); - if (eachElement.getAttribute(attribute).equals(value)) - return eachElement; - } - } - return null; - } - - /** * Adds/replaces the xml entity in the shared configuration we don't need to trigger the change * listener for this modification, so it's ok to operate on the original configuration object */ diff --git a/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java b/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java index 6927d2f..221e154 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java +++ b/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java @@ -51,6 +51,7 @@ public class JAXBService { marshaller = jaxbContext.createMarshaller(); unmarshaller = jaxbContext.createUnmarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true); String schemas = Arrays.stream(xsdRootClasses).map(c -> { XSDRootElement element = c.getAnnotation(XSDRootElement.class); @@ -69,7 +70,7 @@ public class JAXBService { public void validateWith(URL url) { SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - Schema schema = null; + Schema schema; try { schema = factory.newSchema(url); } catch (SAXException e) { @@ -88,6 +89,7 @@ public class JAXBService { public String marshall(Object object) { StringWriter sw = new StringWriter(); try { + sw.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"); marshaller.marshal(object, sw); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommand.java index 9c24efe..6d8175d 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommand.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommand.java @@ -26,7 +26,6 @@ import org.apache.geode.cache.CacheWriter; import org.apache.geode.cache.CustomExpiry; import org.apache.geode.cache.ExpirationAction; import org.apache.geode.distributed.DistributedMember; -import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService; import org.apache.geode.internal.cache.InternalCache; import org.apache.geode.management.cli.CliMetaData; import org.apache.geode.management.cli.ConverterHint; @@ -139,7 +138,7 @@ public class AlterRegionCommand extends InternalGfshCommand { XmlEntity xmlEntity = findXmlEntity(regionAlterResults); if (xmlEntity != null) { persistClusterConfiguration(result, - () -> ((InternalConfigurationPersistenceService) getConfigurationPersistenceService()) + () -> getConfigurationPersistenceService() .addXmlEntity(xmlEntity, groups)); } return result; diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java index b28569a..4686f01 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java @@ -39,9 +39,12 @@ import org.apache.geode.cache.ExpirationAction; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.configuration.CacheConfig; +import org.apache.geode.cache.configuration.RegionConfig; import org.apache.geode.cache.execute.ResultCollector; import org.apache.geode.distributed.DistributedMember; import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.logging.LogService; import org.apache.geode.management.DistributedRegionMXBean; import org.apache.geode.management.DistributedSystemMXBean; import org.apache.geode.management.ManagementService; @@ -50,11 +53,13 @@ import org.apache.geode.management.RegionMXBean; import org.apache.geode.management.cli.CliMetaData; import org.apache.geode.management.cli.ConverterHint; import org.apache.geode.management.cli.Result; +import org.apache.geode.management.cli.SingleGfshCommand; import org.apache.geode.management.internal.cli.AbstractCliAroundInterceptor; import org.apache.geode.management.internal.cli.CliUtil; import org.apache.geode.management.internal.cli.GfshParseResult; import org.apache.geode.management.internal.cli.LogWrapper; import org.apache.geode.management.internal.cli.domain.ClassName; +import org.apache.geode.management.internal.cli.domain.RegionConfigFactory; import org.apache.geode.management.internal.cli.exceptions.EntityExistsException; import org.apache.geode.management.internal.cli.functions.CliFunctionResult; import org.apache.geode.management.internal.cli.functions.FetchRegionAttributesFunction; @@ -63,18 +68,18 @@ import org.apache.geode.management.internal.cli.functions.RegionCreateFunction; import org.apache.geode.management.internal.cli.functions.RegionFunctionArgs; import org.apache.geode.management.internal.cli.i18n.CliStrings; import org.apache.geode.management.internal.cli.result.ResultBuilder; +import org.apache.geode.management.internal.cli.result.model.ResultModel; import org.apache.geode.management.internal.cli.util.RegionPath; -import org.apache.geode.management.internal.configuration.domain.XmlEntity; import org.apache.geode.management.internal.security.ResourceOperation; import org.apache.geode.security.ResourcePermission; -public class CreateRegionCommand extends InternalGfshCommand { +public class CreateRegionCommand extends SingleGfshCommand { @CliCommand(value = CliStrings.CREATE_REGION, help = CliStrings.CREATE_REGION__HELP) @CliMetaData(relatedTopic = CliStrings.TOPIC_GEODE_REGION, interceptor = "org.apache.geode.management.internal.cli.commands.CreateRegionCommand$Interceptor") @ResourceOperation(resource = ResourcePermission.Resource.DATA, operation = ResourcePermission.Operation.MANAGE) - public Result createRegion( + public ResultModel createRegion( @CliOption(key = CliStrings.CREATE_REGION__REGION, mandatory = true, optionContext = ConverterHint.REGION_PATH, help = CliStrings.CREATE_REGION__REGION__HELP) String regionPath, @@ -180,15 +185,13 @@ public class CreateRegionCommand extends InternalGfshCommand { help = CliStrings.CREATE_REGION__VALUECONSTRAINT__HELP) String valueConstraint // NOTICE: keep the region attributes params in alphabetical order ) { - Result result; - if (regionShortcut != null && templateRegion != null) { - return ResultBuilder.createUserErrorResult( + return ResultModel.createError( CliStrings.CREATE_REGION__MSG__ONLY_ONE_OF_REGIONSHORTCUT_AND_USEATTRIBUESFROM_CAN_BE_SPECIFIED); } if (regionShortcut == null && templateRegion == null) { - return ResultBuilder.createUserErrorResult( + return ResultModel.createError( CliStrings.CREATE_REGION__MSG__ONE_OF_REGIONSHORTCUT_AND_USEATTRIBUTESFROM_IS_REQUIRED); } @@ -217,6 +220,7 @@ public class CreateRegionCommand extends InternalGfshCommand { // we first make sure E and C have the compatible data policy if (regionShortcut.isPartition() && !existingDataPolicy.contains("PARTITION")) { + LogService.getLogger().info("Create region command: got EntityExists exception"); throw new EntityExistsException("The existing region is not a partitioned region", ifNotExists); } @@ -244,7 +248,7 @@ public class CreateRegionCommand extends InternalGfshCommand { String parentRegionPath = regionPathData.getParent(); if (parentRegionPath != null && !Region.SEPARATOR.equals(parentRegionPath)) { if (!regionExists(cache, parentRegionPath)) { - return ResultBuilder.createUserErrorResult( + return ResultModel.createError( CliStrings.format(CliStrings.CREATE_REGION__MSG__PARENT_REGION_FOR_0_DOES_NOT_EXIST, new Object[] {regionPath})); } @@ -282,16 +286,17 @@ public class CreateRegionCommand extends InternalGfshCommand { RegionAttributes<?, ?> regionAttributes = null; if (regionShortcut != null) { if (!regionShortcut.name().startsWith("PARTITION") && functionArgs.hasPartitionAttributes()) { - return ResultBuilder.createUserErrorResult(CliStrings.format( + return ResultModel.createError(CliStrings.format( CliStrings.CREATE_REGION__MSG__OPTION_0_CAN_BE_USED_ONLY_FOR_PARTITIONEDREGION, functionArgs.getPartitionArgs().getUserSpecifiedPartitionAttributes()) + " " + CliStrings.format(CliStrings.CREATE_REGION__MSG__0_IS_NOT_A_PARITIONEDREGION, regionPath)); } functionArgs.setRegionShortcut(regionShortcut); + functionArgs.setRegionAttributes(cache.getRegionAttributes(regionShortcut.toString())); } else { // templateRegion != null if (!regionExists(cache, templateRegion)) { - return ResultBuilder.createUserErrorResult(CliStrings.format( + return ResultModel.createError(CliStrings.format( CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_REGION_PATH_FOR_0_REGIONPATH_1_NOT_FOUND, CliStrings.CREATE_REGION__USEATTRIBUTESFROM, templateRegion)); } @@ -299,14 +304,14 @@ public class CreateRegionCommand extends InternalGfshCommand { RegionAttributesWrapper<?, ?> wrappedAttributes = getRegionAttributes(cache, templateRegion); if (wrappedAttributes == null) { - return ResultBuilder.createGemFireErrorResult(CliStrings.format( + return ResultModel.createError(CliStrings.format( CliStrings.CREATE_REGION__MSG__COULD_NOT_RETRIEVE_REGION_ATTRS_FOR_PATH_0_VERIFY_REGION_EXISTS, templateRegion)); } if (wrappedAttributes.getRegionAttributes().getPartitionAttributes() == null && functionArgs.hasPartitionAttributes()) { - return ResultBuilder.createUserErrorResult(CliStrings.format( + return ResultModel.createError(CliStrings.format( CliStrings.CREATE_REGION__MSG__OPTION_0_CAN_BE_USED_ONLY_FOR_PARTITIONEDREGION, functionArgs.getPartitionArgs().getUserSpecifiedPartitionAttributes()) + " " + CliStrings.format(CliStrings.CREATE_REGION__MSG__0_IS_NOT_A_PARITIONEDREGION, @@ -358,14 +363,14 @@ public class CreateRegionCommand extends InternalGfshCommand { DistributedRegionMXBean distributedRegionMXBean = mgmtService.getDistributedRegionMXBean(prColocatedWith); if (distributedRegionMXBean == null) { - return ResultBuilder.createUserErrorResult(CliStrings.format( + return ResultModel.createError(CliStrings.format( CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_REGION_PATH_FOR_0_REGIONPATH_1_NOT_FOUND, CliStrings.CREATE_REGION__COLOCATEDWITH, prColocatedWith)); } String regionType = distributedRegionMXBean.getRegionType(); if (!(DataPolicy.PARTITION.toString().equals(regionType) || DataPolicy.PERSISTENT_PARTITION.toString().equals(regionType))) { - return ResultBuilder.createUserErrorResult(CliStrings.format( + return ResultModel.createError(CliStrings.format( CliStrings.CREATE_REGION__MSG__COLOCATEDWITH_REGION_0_IS_NOT_PARTITIONEDREGION, new Object[] {prColocatedWith})); } @@ -377,14 +382,14 @@ public class CreateRegionCommand extends InternalGfshCommand { Set<String> existingGatewaySenders = Arrays.stream(dsMBean.listGatewaySenders()).collect(Collectors.toSet()); if (existingGatewaySenders.size() == 0) { - return ResultBuilder - .createUserErrorResult(CliStrings.CREATE_REGION__MSG__NO_GATEWAYSENDERS_IN_THE_SYSTEM); + return ResultModel + .createError(CliStrings.CREATE_REGION__MSG__NO_GATEWAYSENDERS_IN_THE_SYSTEM); } else { Set<String> specifiedGatewaySenders = Arrays.stream(gatewaySenderIds).collect(Collectors.toSet()); specifiedGatewaySenders.removeAll(existingGatewaySenders); if (!specifiedGatewaySenders.isEmpty()) { - return ResultBuilder.createUserErrorResult(CliStrings.format( + return ResultModel.createError(CliStrings.format( CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_GATEWAYSENDER_ID_UNKNOWN_0, (Object[]) gatewaySenderIds)); } @@ -402,11 +407,11 @@ public class CreateRegionCommand extends InternalGfshCommand { CliStrings.CREATE_REGION__MSG__USE_ATTRIBUTES_FROM_REGION_0_IS_NOT_WITH_PERSISTENCE, new Object[] {String.valueOf(functionArgs.getTemplateRegion())}); - return ResultBuilder.createUserErrorResult(message); + return ResultModel.createError(message); } if (!diskStoreExists(cache, diskStore)) { - return ResultBuilder.createUserErrorResult(CliStrings.format( + return ResultModel.createError(CliStrings.format( CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_DISKSTORE_UNKNOWN_DISKSTORE_0, new Object[] {diskStore})); } @@ -425,9 +430,9 @@ public class CreateRegionCommand extends InternalGfshCommand { // just in case we found no members with this group name if (membersToCreateRegionOn.isEmpty()) { if (groups == null || groups.length == 0) { - return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE); + return ResultModel.createError(CliStrings.NO_MEMBERS_FOUND_MESSAGE); } else { - return ResultBuilder.createUserErrorResult( + return ResultModel.createError( CliStrings.format(CliStrings.CREATE_REGION__MSG__GROUPS_0_ARE_INVALID, (Object[]) groups)); } @@ -436,14 +441,70 @@ public class CreateRegionCommand extends InternalGfshCommand { List<CliFunctionResult> regionCreateResults = executeAndGetFunctionResult( RegionCreateFunction.INSTANCE, functionArgs, membersToCreateRegionOn); - result = ResultBuilder.buildResult(regionCreateResults); - XmlEntity xmlEntity = findXmlEntity(regionCreateResults); - if (xmlEntity != null) { + ResultModel resultModel = ResultModel.createMemberStatusResult(regionCreateResults); + if (resultModel.isSuccessful()) { verifyDistributedRegionMbean(cache, regionPath); - persistClusterConfiguration(result, - () -> getConfigurationPersistenceService().addXmlEntity(xmlEntity, groups)); + RegionConfig config = (new RegionConfigFactory()).generate(functionArgs); + resultModel.setConfigObject(new CreateRegionResultConfig(config, + functionArgs.getRegionPath())); + } + + return resultModel; + } + + private class CreateRegionResultConfig { + RegionConfig getRegionConfig() { + return regionConfig; + } + + String getFullRegionPath() { + return fullRegionPath; + } + + private final RegionConfig regionConfig; + private final String fullRegionPath; + + public CreateRegionResultConfig(RegionConfig regionConfig, String fullRegionPath) { + this.regionConfig = regionConfig; + this.fullRegionPath = fullRegionPath; + } + } + + @Override + public boolean updateConfigForGroup(String group, CacheConfig config, Object configObject) { + if (configObject == null) { + return false; + } + + CreateRegionResultConfig regionResultConfigObject = (CreateRegionResultConfig) configObject; + RegionConfig regionConfig = regionResultConfigObject.getRegionConfig(); + String regionPath = regionResultConfigObject.getFullRegionPath(); + + RegionPath regionPathData = new RegionPath(regionPath); + if (regionPathData.getParent() == null) { + config.getRegions().add(regionConfig); + return true; + } + + String[] regionsOnPath = regionPathData.getRegionsOnParentPath(); + RegionConfig rootConfig = config.getRegions().stream() + .filter(r -> r.getName().equals(regionsOnPath[0])) + .findFirst() + .get(); + + RegionConfig currentConfig = rootConfig; + for (int i = 1; i < regionsOnPath.length; i++) { + final String curRegionName = regionsOnPath[i]; + currentConfig = currentConfig.getRegions() + .stream() + .filter(r -> r.getName().equals(curRegionName)) + .findFirst() + .get(); } - return result; + + currentConfig.getRegions().add(regionConfig); + + return true; } boolean verifyDistributedRegionMbean(InternalCache cache, String regionName) { @@ -655,6 +716,14 @@ public class CreateRegionCommand extends InternalGfshCommand { .format(CliStrings.CREATE_REGION__MSG__INVALID_COMPRESSOR, new Object[] {compressor})); } + Boolean cloningEnabled = + (Boolean) parseResult.getParamValue(CliStrings.CREATE_REGION__CLONINGENABLED); + if (compressor != null && cloningEnabled != null && !cloningEnabled) { + return ResultBuilder.createUserErrorResult(CliStrings + .format(CliStrings.CREATE_REGION__MSG__CANNOT_DISABLE_CLONING_WITH_COMPRESSOR, + new Object[] {compressor})); + } + String diskStore = parseResult.getParamValueAsString(CliStrings.CREATE_REGION__DISKSTORE); if (diskStore != null) { String regionShortcut = diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeGetFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeGetFunction.java new file mode 100644 index 0000000..ebee2db --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeGetFunction.java @@ -0,0 +1,22 @@ +/* + * 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.domain; + +import org.apache.geode.cache.configuration.RegionAttributesType; + +@FunctionalInterface +public interface RegionAttributeGetFunction { + Object getValue(RegionAttributesType attributesType); +} diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeSetFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeSetFunction.java new file mode 100644 index 0000000..051e815 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeSetFunction.java @@ -0,0 +1,22 @@ +/* + * 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.domain; + +import org.apache.geode.cache.configuration.RegionAttributesType; + +@FunctionalInterface +public interface RegionAttributeSetFunction { + void setAttributeValue(RegionAttributesType attributesType); +} diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java new file mode 100644 index 0000000..59a01a7 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java @@ -0,0 +1,331 @@ +/* + * 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.domain; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.apache.geode.cache.RegionAttributes; +import org.apache.geode.cache.configuration.ClassNameType; +import org.apache.geode.cache.configuration.DeclarableType; +import org.apache.geode.cache.configuration.ExpirationAttributesType; +import org.apache.geode.cache.configuration.RegionAttributesType; +import org.apache.geode.cache.configuration.RegionConfig; +import org.apache.geode.management.internal.cli.functions.RegionFunctionArgs; + +public class RegionConfigFactory { + public RegionConfig generate(RegionFunctionArgs args) { + RegionConfig regionConfig = new RegionConfig(); + regionConfig.setName(getLeafRegion(args.getRegionPath())); + + RegionAttributes<?, ?> regionAttributes = args.getRegionAttributes(); + if (args.getKeyConstraint() != null) { + addAttribute(regionConfig, a -> a.setKeyConstraint(args.getKeyConstraint())); + } + + if (args.getValueConstraint() != null) { + addAttribute(regionConfig, a -> a.setValueConstraint(args.getValueConstraint())); + } + + if (args.getStatisticsEnabled() != null) { + addAttribute(regionConfig, a -> a.setStatisticsEnabled(args.getStatisticsEnabled())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setStatisticsEnabled(regionAttributes + .getStatisticsEnabled())); + } + + if (args.getEntryExpirationIdleTime() != null) { + RegionAttributesType.EntryIdleTime entryIdleTime = new RegionAttributesType.EntryIdleTime(); + entryIdleTime.setExpirationAttributes( + args.getEntryExpirationIdleTime().getExpirationAttributes().toConfigType()); + addAttribute(regionConfig, a -> a.setEntryIdleTime(entryIdleTime)); + } else if (regionAttributes != null && + regionAttributes.getEntryIdleTimeout() != null && + !regionAttributes.getEntryIdleTimeout().isDefault()) { + RegionAttributesType.EntryIdleTime entryIdleTime = new RegionAttributesType.EntryIdleTime(); + entryIdleTime.setExpirationAttributes(regionAttributes + .getEntryIdleTimeout().toConfigType()); + addAttribute(regionConfig, a -> a.setEntryIdleTime(entryIdleTime)); + } + + if (args.getEntryIdleTimeCustomExpiry() != null) { + Object maybeEntryIdleAttr = getRegionAttributeValue(regionConfig, a -> a.getEntryIdleTime()); + RegionAttributesType.EntryIdleTime entryIdleTime = + maybeEntryIdleAttr != null ? (RegionAttributesType.EntryIdleTime) maybeEntryIdleAttr + : new RegionAttributesType.EntryIdleTime(); + + ExpirationAttributesType expirationAttributes; + if (entryIdleTime.getExpirationAttributes() == null) { + expirationAttributes = new ExpirationAttributesType(); + expirationAttributes.setTimeout("0"); + } else { + expirationAttributes = entryIdleTime.getExpirationAttributes(); + } + + DeclarableType customExpiry = new DeclarableType(); + customExpiry.setClassName(args.getEntryIdleTimeCustomExpiry().getClassName()); + expirationAttributes.setCustomExpiry(customExpiry); + entryIdleTime.setExpirationAttributes(expirationAttributes); + + if (maybeEntryIdleAttr == null) { + addAttribute(regionConfig, a -> a.setEntryIdleTime(entryIdleTime)); + } + } + + if (args.getEntryExpirationTTL() != null) { + RegionAttributesType.EntryTimeToLive entryExpTime = + new RegionAttributesType.EntryTimeToLive(); + entryExpTime.setExpirationAttributes( + args.getEntryExpirationTTL().getExpirationAttributes().toConfigType()); + addAttribute(regionConfig, a -> a.setEntryTimeToLive(entryExpTime)); + } else if (regionAttributes != null + && regionAttributes.getEntryTimeToLive() != null + && !regionAttributes.getEntryTimeToLive().isDefault()) { + RegionAttributesType.EntryTimeToLive entryExpTime = + new RegionAttributesType.EntryTimeToLive(); + entryExpTime.setExpirationAttributes( + regionAttributes.getEntryTimeToLive().toConfigType()); + addAttribute(regionConfig, a -> a.setEntryTimeToLive(entryExpTime)); + } + + if (args.getRegionExpirationIdleTime() != null) { + RegionAttributesType.RegionIdleTime regionIdleTime = + new RegionAttributesType.RegionIdleTime(); + regionIdleTime.setExpirationAttributes( + args.getRegionExpirationIdleTime().getExpirationAttributes().toConfigType()); + addAttribute(regionConfig, a -> a.setRegionIdleTime(regionIdleTime)); + } else if (regionAttributes != null + && regionAttributes.getRegionIdleTimeout() != null + && !regionAttributes.getRegionIdleTimeout().isDefault()) { + RegionAttributesType.RegionIdleTime regionIdleTime = + new RegionAttributesType.RegionIdleTime(); + regionIdleTime.setExpirationAttributes( + regionAttributes.getRegionIdleTimeout().toConfigType()); + addAttribute(regionConfig, a -> a.setRegionIdleTime(regionIdleTime)); + } + + if (args.getRegionExpirationTTL() != null) { + RegionAttributesType.RegionTimeToLive regionExpTime = + new RegionAttributesType.RegionTimeToLive(); + regionExpTime.setExpirationAttributes( + args.getRegionExpirationTTL().getExpirationAttributes().toConfigType()); + addAttribute(regionConfig, a -> a.setRegionTimeToLive(regionExpTime)); + } else if (regionAttributes != null + && regionAttributes.getRegionTimeToLive() != null + && !regionAttributes.getRegionTimeToLive().isDefault()) { + RegionAttributesType.RegionTimeToLive regionExpTime = + new RegionAttributesType.RegionTimeToLive(); + regionExpTime.setExpirationAttributes( + regionAttributes.getRegionTimeToLive().toConfigType()); + addAttribute(regionConfig, a -> a.setRegionTimeToLive(regionExpTime)); + } + + if (args.getEntryTTLCustomExpiry() != null) { + Object maybeEntryTTLAttr = getRegionAttributeValue(regionConfig, a -> a.getEntryTimeToLive()); + RegionAttributesType.EntryTimeToLive entryTimeToLive = + maybeEntryTTLAttr != null ? (RegionAttributesType.EntryTimeToLive) maybeEntryTTLAttr + : new RegionAttributesType.EntryTimeToLive(); + + ExpirationAttributesType expirationAttributes; + if (entryTimeToLive.getExpirationAttributes() == null) { + expirationAttributes = new ExpirationAttributesType(); + expirationAttributes.setTimeout("0"); + } else { + expirationAttributes = entryTimeToLive.getExpirationAttributes(); + } + + DeclarableType customExpiry = new DeclarableType(); + customExpiry.setClassName(args.getEntryTTLCustomExpiry().getClassName()); + expirationAttributes.setCustomExpiry(customExpiry); + entryTimeToLive.setExpirationAttributes(expirationAttributes); + + if (maybeEntryTTLAttr == null) { + addAttribute(regionConfig, a -> a.setEntryTimeToLive(entryTimeToLive)); + } + } + + if (args.getDiskStore() != null) { + addAttribute(regionConfig, a -> a.setDiskStoreName(args.getDiskStore())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setDiskStoreName(regionAttributes.getDiskStoreName())); + } + + if (args.getDiskSynchronous() != null) { + addAttribute(regionConfig, a -> a.setDiskSynchronous(args.getDiskSynchronous())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setDiskSynchronous(regionAttributes.isDiskSynchronous())); + } + + if (args.getEnableAsyncConflation() != null) { + addAttribute(regionConfig, a -> a.setEnableAsyncConflation(args.getEnableAsyncConflation())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setEnableAsyncConflation(regionAttributes + .getEnableAsyncConflation())); + } + + if (args.getEnableSubscriptionConflation() != null) { + addAttribute(regionConfig, + a -> a.setEnableSubscriptionConflation(args.getEnableSubscriptionConflation())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setEnableSubscriptionConflation(regionAttributes + .getEnableSubscriptionConflation())); + } + + if (args.getConcurrencyChecksEnabled() != null) { + addAttribute(regionConfig, a -> a.setConcurrencyChecksEnabled( + args.getConcurrencyChecksEnabled())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setConcurrencyChecksEnabled(regionAttributes + .getConcurrencyChecksEnabled())); + } + + if (args.getCloningEnabled() != null) { + addAttribute(regionConfig, a -> a.setCloningEnabled(args.getCloningEnabled())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setCloningEnabled(regionAttributes + .getCloningEnabled())); + } + + if (args.getOffHeap() != null) { + addAttribute(regionConfig, a -> a.setOffHeap(args.getOffHeap())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setOffHeap(regionAttributes.getOffHeap())); + } + + if (args.getMcastEnabled() != null) { + addAttribute(regionConfig, a -> a.setMulticastEnabled(args.getMcastEnabled())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setMulticastEnabled(regionAttributes + .getMulticastEnabled())); + } + + if (args.getPartitionArgs() != null) { + RegionAttributesType.PartitionAttributes partitionAttributes = + new RegionAttributesType.PartitionAttributes(); + RegionFunctionArgs.PartitionArgs partitionArgs = args.getPartitionArgs(); + partitionAttributes.setColocatedWith(partitionArgs.getPrColocatedWith()); + partitionAttributes.setLocalMaxMemory(int2string(partitionArgs.getPrLocalMaxMemory())); + partitionAttributes.setRecoveryDelay(long2string(partitionArgs.getPrRecoveryDelay())); + partitionAttributes.setRedundantCopies(int2string(partitionArgs.getPrRedundantCopies())); + partitionAttributes + .setStartupRecoveryDelay(long2string(partitionArgs.getPrStartupRecoveryDelay())); + partitionAttributes.setTotalMaxMemory(long2string(partitionArgs.getPrTotalMaxMemory())); + partitionAttributes.setTotalNumBuckets(int2string(partitionArgs.getPrTotalNumBuckets())); + + if (partitionArgs.getPartitionResolver() != null) { + DeclarableType partitionResolverType = new DeclarableType(); + partitionResolverType.setClassName(partitionArgs.getPartitionResolver()); + partitionAttributes.setPartitionResolver(partitionResolverType); + } + + addAttribute(regionConfig, a -> a.setPartitionAttributes(partitionAttributes)); + } else if (regionAttributes != null && regionAttributes.getPartitionAttributes() != null) { + addAttribute(regionConfig, a -> a.setPartitionAttributes( + regionAttributes.getPartitionAttributes().convertToConfigPartitionAttributes())); + } + + if (args.getGatewaySenderIds() != null && !args.getGatewaySenderIds().isEmpty()) { + addAttribute(regionConfig, a -> a.setGatewaySenderIds(String.join(",", + args.getGatewaySenderIds()))); + } + + if (args.getEvictionAttributes() != null) { + addAttribute(regionConfig, a -> a.setEvictionAttributes( + args.getEvictionAttributes().convertToConfigEvictionAttributes())); + } else if (regionAttributes != null && + regionAttributes.getEvictionAttributes() != null && + !regionAttributes.getEvictionAttributes().isEmpty()) { + addAttribute(regionConfig, a -> a.setEvictionAttributes( + regionAttributes.getEvictionAttributes().convertToConfigEvictionAttributes())); + } + + if (args.getAsyncEventQueueIds() != null && !args.getAsyncEventQueueIds().isEmpty()) { + addAttribute(regionConfig, + a -> a.setAsyncEventQueueIds(String.join(",", args.getAsyncEventQueueIds()))); + } + + if (args.getCacheListeners() != null && !args.getCacheListeners().isEmpty()) { + addAttribute(regionConfig, a -> a.getCacheListeners().addAll( + args.getCacheListeners().stream().map(l -> { + DeclarableType declarableType = new DeclarableType(); + declarableType.setClassName(l.getClassName()); + return declarableType; + }).collect(Collectors.toList()))); + } + + if (args.getCacheLoader() != null) { + DeclarableType declarableType = new DeclarableType(); + declarableType.setClassName(args.getCacheLoader().getClassName()); + addAttribute(regionConfig, a -> a.setCacheLoader(declarableType)); + } + + if (args.getCacheWriter() != null) { + DeclarableType declarableType = new DeclarableType(); + declarableType.setClassName(args.getCacheWriter().getClassName()); + addAttribute(regionConfig, a -> a.setCacheWriter(declarableType)); + } + + if (args.getCompressor() != null) { + addAttribute(regionConfig, a -> a.setCompressor(new ClassNameType(args.getCompressor()))); + addAttribute(regionConfig, a -> a.setCloningEnabled(true)); + } + + if (args.getConcurrencyLevel() != null) { + addAttribute(regionConfig, a -> a.setConcurrencyLevel(args.getConcurrencyLevel().toString())); + } else if (regionAttributes != null) { + addAttribute(regionConfig, a -> a.setConcurrencyLevel(Integer.toString( + regionAttributes.getConcurrencyLevel()))); + } + + if (regionAttributes != null && regionAttributes.getDataPolicy() != null) { + addAttribute(regionConfig, + a -> a.setDataPolicy(regionAttributes.getDataPolicy().toConfigType())); + } + + return regionConfig; + } + + private String int2string(Integer i) { + return Optional.ofNullable(i).map(j -> j.toString()).orElse(null); + } + + private String long2string(Long i) { + return Optional.ofNullable(i).map(j -> j.toString()).orElse(null); + } + + private String getLeafRegion(String fullPath) { + String regionPath = fullPath; + String[] regions = regionPath.split("/"); + + return regions[regions.length - 1]; + } + + private void addAttribute(RegionConfig config, RegionAttributeSetFunction func) { + final List<RegionAttributesType> regionAttributes = config.getRegionAttributes(); + if (regionAttributes.isEmpty()) { + regionAttributes.add(new RegionAttributesType()); + } + + func.setAttributeValue(regionAttributes.get(0)); + } + + private Object getRegionAttributeValue(RegionConfig config, RegionAttributeGetFunction function) { + return config.getRegionAttributes().stream() + .findFirst() + .map(a -> function.getValue(a)) + .orElse(null); + } +} diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionAlterFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionAlterFunction.java index fe53185..d568041 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionAlterFunction.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionAlterFunction.java @@ -111,8 +111,8 @@ public class RegionAlterFunction implements InternalFunction { AttributesMutator mutator = region.getAttributesMutator(); - if (regionAlterArgs.isCloningEnabled() != null) { - mutator.setCloningEnabled(regionAlterArgs.isCloningEnabled()); + if (regionAlterArgs.getCloningEnabled() != null) { + mutator.setCloningEnabled(regionAlterArgs.getCloningEnabled()); if (logger.isDebugEnabled()) { logger.debug("Region successfully altered - cloning"); } @@ -128,7 +128,7 @@ public class RegionAlterFunction implements InternalFunction { // Alter expiration attributes final RegionFunctionArgs.ExpirationAttrs newEntryExpirationIdleTime = regionAlterArgs.getEntryExpirationIdleTime(); - if (newEntryExpirationIdleTime.isTimeOrActionSet()) { + if (newEntryExpirationIdleTime != null && newEntryExpirationIdleTime.isTimeOrActionSet()) { mutator.setEntryIdleTimeout( newEntryExpirationIdleTime.getExpirationAttributes(region.getEntryIdleTimeout())); if (logger.isDebugEnabled()) { @@ -138,7 +138,7 @@ public class RegionAlterFunction implements InternalFunction { final RegionFunctionArgs.ExpirationAttrs newEntryExpirationTTL = regionAlterArgs.getEntryExpirationTTL(); - if (newEntryExpirationTTL.isTimeOrActionSet()) { + if (newEntryExpirationTTL != null && newEntryExpirationTTL.isTimeOrActionSet()) { mutator.setEntryTimeToLive( newEntryExpirationTTL.getExpirationAttributes(region.getEntryTimeToLive())); if (logger.isDebugEnabled()) { @@ -167,7 +167,7 @@ public class RegionAlterFunction implements InternalFunction { final RegionFunctionArgs.ExpirationAttrs newRegionExpirationIdleTime = regionAlterArgs.getRegionExpirationIdleTime(); - if (newRegionExpirationIdleTime.isTimeOrActionSet()) { + if (newRegionExpirationIdleTime != null && newRegionExpirationIdleTime.isTimeOrActionSet()) { mutator.setRegionIdleTimeout( newRegionExpirationIdleTime.getExpirationAttributes(region.getRegionIdleTimeout())); if (logger.isDebugEnabled()) { @@ -177,7 +177,7 @@ public class RegionAlterFunction implements InternalFunction { final RegionFunctionArgs.ExpirationAttrs newRegionExpirationTTL = regionAlterArgs.getRegionExpirationTTL(); - if (newRegionExpirationTTL.isTimeOrActionSet()) { + if (newRegionExpirationTTL != null && newRegionExpirationTTL.isTimeOrActionSet()) { mutator.setRegionTimeToLive( newRegionExpirationTTL.getExpirationAttributes(region.getRegionTimeToLive())); if (logger.isDebugEnabled()) { diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionCreateFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionCreateFunction.java index 26ca760..353ee30 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionCreateFunction.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionCreateFunction.java @@ -16,6 +16,7 @@ package org.apache.geode.management.internal.cli.functions; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.Set; import org.apache.commons.lang3.StringUtils; @@ -84,21 +85,22 @@ public class RegionCreateFunction implements InternalFunction { if (regionCreateArgs.isIfNotExists()) { 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, - memberNameOrId, regionCreateArgs.getRegionPath()))); + resultSender + .lastResult(new CliFunctionResult(memberNameOrId, CliFunctionResult.StatusState.OK, + CliStrings.format( + CliStrings.CREATE_REGION__MSG__SKIPPING_0_REGION_PATH_1_ALREADY_EXISTS, + memberNameOrId, regionCreateArgs.getRegionPath()))); return; } } try { Region<?, ?> createdRegion = createRegion(cache, regionCreateArgs); - XmlEntity xmlEntity = getXmlEntityForRegion(createdRegion); - resultSender.lastResult(new CliFunctionResult(memberNameOrId, xmlEntity, - CliStrings.format(CliStrings.CREATE_REGION__MSG__REGION_0_CREATED_ON_1, - createdRegion.getFullPath(), memberNameOrId))); + resultSender + .lastResult(new CliFunctionResult(memberNameOrId, CliFunctionResult.StatusState.OK, + CliStrings.format(CliStrings.CREATE_REGION__MSG__REGION_0_CREATED_ON_1, + createdRegion.getFullPath(), memberNameOrId))); } catch (IllegalStateException e) { String exceptionMsg = e.getMessage(); String localizedString = @@ -154,18 +156,9 @@ public class RegionCreateFunction implements InternalFunction { final RegionShortcut regionShortcut = regionCreateArgs.getRegionShortcut(); // create the region factory using the arguments - boolean isPartitioned = false; - RegionFactory<K, V> factory = null; - RegionAttributes<K, V> regionAttributes = null; - if (regionShortcut != null) { - regionAttributes = cache.getRegionAttributes(regionShortcut.toString()); - regionCreateArgs.setRegionAttributes(regionAttributes); - } else { - regionAttributes = regionCreateArgs.getRegionAttributes(); - } - - isPartitioned = regionAttributes.getPartitionAttributes() != null; - factory = cache.createRegionFactory(regionAttributes); + RegionAttributes<K, V> regionAttributes = regionCreateArgs.getRegionAttributes(); + boolean isPartitioned = regionAttributes.getPartitionAttributes() != null; + RegionFactory<K, V> factory = cache.createRegionFactory(regionAttributes); if (isPartitioned) { PartitionAttributes<K, V> partitionAttributes = @@ -197,7 +190,7 @@ public class RegionCreateFunction implements InternalFunction { // Expiration attributes final RegionFunctionArgs.ExpirationAttrs entryExpirationIdleTime = regionCreateArgs.getEntryExpirationIdleTime(); - if (entryExpirationIdleTime.isTimeOrActionSet()) { + if (entryExpirationIdleTime != null && entryExpirationIdleTime.isTimeOrActionSet()) { factory.setEntryIdleTimeout(entryExpirationIdleTime.getExpirationAttributes()); } @@ -213,21 +206,23 @@ public class RegionCreateFunction implements InternalFunction { final RegionFunctionArgs.ExpirationAttrs entryExpirationTTL = regionCreateArgs.getEntryExpirationTTL(); - if (entryExpirationTTL.isTimeOrActionSet()) { + if (entryExpirationTTL != null && entryExpirationTTL.isTimeOrActionSet()) { factory.setEntryTimeToLive(entryExpirationTTL.getExpirationAttributes()); } final RegionFunctionArgs.ExpirationAttrs regionExpirationIdleTime = regionCreateArgs.getRegionExpirationIdleTime(); - if (regionExpirationIdleTime.isTimeOrActionSet()) { + if (regionExpirationIdleTime != null && regionExpirationIdleTime.isTimeOrActionSet()) { factory.setRegionIdleTimeout(regionExpirationIdleTime.getExpirationAttributes()); } final RegionFunctionArgs.ExpirationAttrs regionExpirationTTL = regionCreateArgs.getRegionExpirationTTL(); - if (regionExpirationTTL.isTimeOrActionSet()) { + if (regionExpirationTTL != null && regionExpirationTTL.isTimeOrActionSet()) { factory.setRegionTimeToLive(regionExpirationTTL.getExpirationAttributes()); } - EvictionAttributes evictionAttributes = regionCreateArgs.getEvictionAttributes(); + EvictionAttributes evictionAttributes = Optional + .ofNullable(regionCreateArgs.getEvictionAttributes()) + .map(a -> a.convertToEvictionAttributes()).orElse(null); if (evictionAttributes != null) { ObjectSizer sizer = evictionAttributes.getObjectSizer(); if (sizer != null && !(sizer instanceof Declarable)) { @@ -243,24 +238,24 @@ public class RegionCreateFunction implements InternalFunction { factory.setDiskStoreName(diskStore); } - if (regionCreateArgs.isDiskSynchronous() != null) { - factory.setDiskSynchronous(regionCreateArgs.isDiskSynchronous()); + if (regionCreateArgs.getDiskSynchronous() != null) { + factory.setDiskSynchronous(regionCreateArgs.getDiskSynchronous()); } - if (regionCreateArgs.isOffHeap() != null) { - factory.setOffHeap(regionCreateArgs.isOffHeap()); + if (regionCreateArgs.getOffHeap() != null) { + factory.setOffHeap(regionCreateArgs.getOffHeap()); } - if (regionCreateArgs.isStatisticsEnabled() != null) { - factory.setStatisticsEnabled(regionCreateArgs.isStatisticsEnabled()); + if (regionCreateArgs.getStatisticsEnabled() != null) { + factory.setStatisticsEnabled(regionCreateArgs.getStatisticsEnabled()); } - if (regionCreateArgs.isEnableAsyncConflation() != null) { - factory.setEnableAsyncConflation(regionCreateArgs.isEnableAsyncConflation()); + if (regionCreateArgs.getEnableAsyncConflation() != null) { + factory.setEnableAsyncConflation(regionCreateArgs.getEnableAsyncConflation()); } - if (regionCreateArgs.isEnableSubscriptionConflation() != null) { - factory.setEnableSubscriptionConflation(regionCreateArgs.isEnableSubscriptionConflation()); + if (regionCreateArgs.getEnableSubscriptionConflation() != null) { + factory.setEnableSubscriptionConflation(regionCreateArgs.getEnableSubscriptionConflation()); } // Gateway Sender Ids @@ -279,20 +274,20 @@ public class RegionCreateFunction implements InternalFunction { } } - if (regionCreateArgs.isConcurrencyChecksEnabled() != null) { - factory.setConcurrencyChecksEnabled(regionCreateArgs.isConcurrencyChecksEnabled()); + if (regionCreateArgs.getConcurrencyChecksEnabled() != null) { + factory.setConcurrencyChecksEnabled(regionCreateArgs.getConcurrencyChecksEnabled()); } if (regionCreateArgs.getConcurrencyLevel() != null) { factory.setConcurrencyLevel(regionCreateArgs.getConcurrencyLevel()); } - if (regionCreateArgs.isCloningEnabled() != null) { - factory.setCloningEnabled(regionCreateArgs.isCloningEnabled()); + if (regionCreateArgs.getCloningEnabled() != null) { + factory.setCloningEnabled(regionCreateArgs.getCloningEnabled()); } - if (regionCreateArgs.isMcastEnabled() != null) { - factory.setMulticastEnabled(regionCreateArgs.isMcastEnabled()); + if (regionCreateArgs.getMcastEnabled() != null) { + factory.setMulticastEnabled(regionCreateArgs.getMcastEnabled()); } // Set plugins @@ -341,9 +336,8 @@ public class RegionCreateFunction implements InternalFunction { @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; + PartitionAttributesFactory<K, V> prAttrFactory; PartitionAttributes<K, V> partitionAttributes = regionAttributes.getPartitionAttributes(); if (partitionAttributes != null) { @@ -352,46 +346,49 @@ public class RegionCreateFunction implements InternalFunction { prAttrFactory = new PartitionAttributesFactory<>(); } - 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_DOES_NOT_EXIST, colocatedWith)); + if (regionCreateArgs.hasPartitionAttributes()) { + RegionFunctionArgs.PartitionArgs partitionArgs = regionCreateArgs.getPartitionArgs(); + 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_DOES_NOT_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 (!colocatedWithRegion.getAttributes().getDataPolicy().withPartitioning()) { - throw new IllegalArgumentException(CliStrings.format( - CliStrings.CREATE_REGION__MSG__COLOCATEDWITH_REGION_0_IS_NOT_PARTITIONEDREGION, - colocatedWith)); + if (partitionArgs.getPrLocalMaxMemory() != null) { + prAttrFactory.setLocalMaxMemory(partitionArgs.getPrLocalMaxMemory()); + } + if (partitionArgs.getPrTotalMaxMemory() != null) { + prAttrFactory.setTotalMaxMemory(partitionArgs.getPrTotalMaxMemory()); + } + if (partitionArgs.getPrTotalNumBuckets() != null) { + prAttrFactory.setTotalNumBuckets(partitionArgs.getPrTotalNumBuckets()); + } + if (partitionArgs.getPrRedundantCopies() != null) { + prAttrFactory.setRedundantCopies(partitionArgs.getPrRedundantCopies()); + } + if (partitionArgs.getPrRecoveryDelay() != null) { + prAttrFactory.setRecoveryDelay(partitionArgs.getPrRecoveryDelay()); + } + if (partitionArgs.getPrStartupRecoveryDelay() != null) { + prAttrFactory.setStartupRecoveryDelay(partitionArgs.getPrStartupRecoveryDelay()); } - prAttrFactory.setColocatedWith(colocatedWith); - } - if (partitionArgs.getPrLocalMaxMemory() != null) { - prAttrFactory.setLocalMaxMemory(partitionArgs.getPrLocalMaxMemory()); - } - if (partitionArgs.getPrTotalMaxMemory() != null) { - prAttrFactory.setTotalMaxMemory(partitionArgs.getPrTotalMaxMemory()); - } - if (partitionArgs.getPrTotalNumBuckets() != null) { - prAttrFactory.setTotalNumBuckets(partitionArgs.getPrTotalNumBuckets()); - } - if (partitionArgs.getPrRedundantCopies() != null) { - prAttrFactory.setRedundantCopies(partitionArgs.getPrRedundantCopies()); - } - if (partitionArgs.getPrRecoveryDelay() != null) { - prAttrFactory.setRecoveryDelay(partitionArgs.getPrRecoveryDelay()); - } - if (partitionArgs.getPrStartupRecoveryDelay() != null) { - prAttrFactory.setStartupRecoveryDelay(partitionArgs.getPrStartupRecoveryDelay()); - } - if (regionCreateArgs.getPartitionArgs().getPartitionResolver() != null) { - Class<PartitionResolver> partitionResolverClass = - forName(regionCreateArgs.getPartitionArgs().getPartitionResolver(), - CliStrings.CREATE_REGION__PARTITION_RESOLVER); - prAttrFactory - .setPartitionResolver((PartitionResolver<K, V>) newInstance(partitionResolverClass, - CliStrings.CREATE_REGION__PARTITION_RESOLVER)); + if (regionCreateArgs.getPartitionArgs().getPartitionResolver() != null) { + Class<PartitionResolver> partitionResolverClass = + forName(regionCreateArgs.getPartitionArgs().getPartitionResolver(), + CliStrings.CREATE_REGION__PARTITION_RESOLVER); + prAttrFactory + .setPartitionResolver((PartitionResolver<K, V>) newInstance(partitionResolverClass, + CliStrings.CREATE_REGION__PARTITION_RESOLVER)); + } } return prAttrFactory.create(); } diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgs.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgs.java index 948ba29..21d975d 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgs.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgs.java @@ -33,6 +33,8 @@ import org.apache.geode.cache.ExpirationAction; import org.apache.geode.cache.ExpirationAttributes; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.configuration.EnumActionDestroyOverflow; +import org.apache.geode.cache.configuration.RegionAttributesType; import org.apache.geode.cache.util.ObjectSizer; import org.apache.geode.internal.ClassPathLoader; import org.apache.geode.management.internal.cli.domain.ClassName; @@ -80,9 +82,7 @@ public class RegionFunctionArgs implements Serializable { private Boolean offHeap; private RegionAttributes<?, ?> regionAttributes; - public RegionFunctionArgs() { - this.partitionArgs = new PartitionArgs(); - } + public RegionFunctionArgs() {} public void setRegionPath(String regionPath) { this.regionPath = regionPath; @@ -114,18 +114,34 @@ public class RegionFunctionArgs implements Serializable { } public void setEntryExpirationIdleTime(Integer timeout, ExpirationAction action) { + if (timeout == null && action == null) { + return; + } + this.entryExpirationIdleTime = new ExpirationAttrs(timeout, action); } public void setEntryExpirationTTL(Integer timeout, ExpirationAction action) { + if (timeout == null && action == null) { + return; + } + this.entryExpirationTTL = new ExpirationAttrs(timeout, action); } public void setRegionExpirationIdleTime(Integer timeout, ExpirationAction action) { + if (timeout == null && action == null) { + return; + } + this.regionExpirationIdleTime = new ExpirationAttrs(timeout, action); } public void setRegionExpirationTTL(Integer timeout, ExpirationAction action) { + if (timeout == null && action == null) { + return; + } + this.regionExpirationTTL = new ExpirationAttrs(timeout, action); } @@ -199,6 +215,19 @@ public class RegionFunctionArgs implements Serializable { public void setPartitionArgs(String prColocatedWith, Integer prLocalMaxMemory, Long prRecoveryDelay, Integer prRedundantCopies, Long prStartupRecoveryDelay, Long prTotalMaxMemory, Integer prTotalNumBuckets, String partitionResolver) { + if (prColocatedWith == null && + prLocalMaxMemory == null && + prRecoveryDelay == null && + prRedundantCopies == null && + prStartupRecoveryDelay == null && + prTotalMaxMemory == null && + prTotalNumBuckets == null && + partitionResolver == null) { + return; + } + if (partitionArgs == null) { + partitionArgs = new PartitionArgs(); + } partitionArgs.setPrColocatedWith(prColocatedWith); partitionArgs.setPrLocalMaxMemory(prLocalMaxMemory); partitionArgs.setPrRecoveryDelay(prRecoveryDelay); @@ -270,7 +299,7 @@ public class RegionFunctionArgs implements Serializable { /** * @return the statisticsEnabled */ - public Boolean isStatisticsEnabled() { + public Boolean getStatisticsEnabled() { return this.statisticsEnabled; } @@ -312,25 +341,25 @@ public class RegionFunctionArgs implements Serializable { /** * @return the diskSynchronous */ - public Boolean isDiskSynchronous() { + public Boolean getDiskSynchronous() { return this.diskSynchronous; } - public Boolean isOffHeap() { + public Boolean getOffHeap() { return this.offHeap; } /** * @return the enableAsyncConflation */ - public Boolean isEnableAsyncConflation() { + public Boolean getEnableAsyncConflation() { return this.enableAsyncConflation; } /** * @return the enableSubscriptionConflation */ - public Boolean isEnableSubscriptionConflation() { + public Boolean getEnableSubscriptionConflation() { return this.enableSubscriptionConflation; } @@ -381,21 +410,21 @@ public class RegionFunctionArgs implements Serializable { /** * @return the concurrencyChecksEnabled */ - public Boolean isConcurrencyChecksEnabled() { + public Boolean getConcurrencyChecksEnabled() { return this.concurrencyChecksEnabled; } /** * @return the cloningEnabled */ - public Boolean isCloningEnabled() { + public Boolean getCloningEnabled() { return this.cloningEnabled; } /** * @return the mcastEnabled setting */ - public Boolean isMcastEnabled() { + public Boolean getMcastEnabled() { return this.mcastEnabled; } @@ -415,7 +444,7 @@ public class RegionFunctionArgs implements Serializable { * @return the partitionArgs */ public boolean hasPartitionAttributes() { - return this.partitionArgs.hasPartitionAttributes(); + return this.partitionArgs != null && this.partitionArgs.hasPartitionAttributes(); } /** @@ -439,8 +468,8 @@ public class RegionFunctionArgs implements Serializable { return this.compressor; } - public EvictionAttributes getEvictionAttributes() { - return evictionAttributes != null ? evictionAttributes.convertToEvictionAttributes() : null; + public EvictionAttrs getEvictionAttributes() { + return this.evictionAttributes; } /** @@ -601,6 +630,35 @@ public class RegionFunctionArgs implements Serializable { return EvictionAttributes.createLRUEntryAttributes(maxEntryCount, action); } } + + public RegionAttributesType.EvictionAttributes convertToConfigEvictionAttributes() { + RegionAttributesType.EvictionAttributes configAttributes = + new RegionAttributesType.EvictionAttributes(); + EnumActionDestroyOverflow action = EnumActionDestroyOverflow.fromValue(evictionAction); + + if (maxMemory == null && maxEntryCount == null) { + RegionAttributesType.EvictionAttributes.LruHeapPercentage heapPercentage = + new RegionAttributesType.EvictionAttributes.LruHeapPercentage(); + heapPercentage.setAction(action); + heapPercentage.setClassName(objectSizer); + configAttributes.setLruHeapPercentage(heapPercentage); + } else if (maxMemory != null) { + RegionAttributesType.EvictionAttributes.LruMemorySize memorySize = + new RegionAttributesType.EvictionAttributes.LruMemorySize(); + memorySize.setAction(action); + memorySize.setClassName(objectSizer); + memorySize.setMaximum(maxMemory.toString()); + configAttributes.setLruMemorySize(memorySize); + } else { + RegionAttributesType.EvictionAttributes.LruEntryCount entryCount = + new RegionAttributesType.EvictionAttributes.LruEntryCount(); + entryCount.setAction(action); + entryCount.setMaximum(maxEntryCount.toString()); + configAttributes.setLruEntryCount(entryCount); + } + + return configAttributes; + } } diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java index a7cbd16..bd96248 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java @@ -946,6 +946,8 @@ public class CliStrings { public static final String CREATE_REGION__TOTALNUMBUCKETS__HELP = "Sets the total number of hash buckets to be used by the region in all processes. (Default: " + PartitionAttributesFactory.GLOBAL_MAX_BUCKETS_DEFAULT + ")."; + public static final String CREATE_REGION__MSG__CANNOT_DISABLE_CLONING_WITH_COMPRESSOR = + "Cannot set enable-cloning to false when compressor is provided"; public static final String CREATE_REGION__MSG__SPECIFY_VALID_REGION_PATH = "Specify a valid " + CliStrings.CREATE_REGION__REGION; public static final String CREATE_REGION__MSG__PARENT_REGION_FOR_0_DOES_NOT_EXIST = diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionPath.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionPath.java index aac49bf..3bd548b 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionPath.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionPath.java @@ -14,7 +14,9 @@ */ package org.apache.geode.management.internal.cli.util; +import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; import org.apache.geode.cache.Cache; import org.apache.geode.cache.Region; @@ -67,6 +69,20 @@ public class RegionPath { return regionParentPath; } + public String[] getRegionsOnParentPath() { + String[] regionsOnPath = getParent().split(Region.SEPARATOR); + + // Ignore preceding separator if there is one + int start = regionsOnPath[0] == null || regionsOnPath[0].isEmpty() ? 1 : 0; + + List<String> regions = new ArrayList<>(); + for (int i = start; i < regionsOnPath.length; i++) { + regions.add(regionsOnPath[i]); + } + + return regions.toArray(new String[] {}); + } + /** * @return Parent RegionPath of this RegionPath. null if this is a root region */ diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java b/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java index 8d38c49..d3649f1 100644 --- a/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java +++ b/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java @@ -41,9 +41,9 @@ import org.apache.geode.cache.query.QueryService; import org.apache.geode.cache.query.RegionNotFoundException; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.hll.HyperLogLogPlus; -import org.apache.geode.management.cli.Result; import org.apache.geode.management.cli.Result.Status; import org.apache.geode.management.internal.cli.commands.CreateRegionCommand; +import org.apache.geode.management.internal.cli.result.model.ResultModel; import org.apache.geode.redis.GeodeRedisServer; import org.apache.geode.redis.internal.executor.ExpirationExecutor; import org.apache.geode.redis.internal.executor.ListQuery; @@ -399,17 +399,19 @@ public class RegionProvider implements Closeable { return r; do { createRegionCmd.setCache(cache); - Result result = createRegionCmd.createRegion(regionPath, defaultRegionType, null, null, true, - null, null, null, null, null, null, null, null, false, false, true, false, false, false, - true, null, null, null, null, null, null, null, null, null, null, null, null, null, false, - null, null, null, null, null, null, null, null, null, null, null); + ResultModel resultModel = + createRegionCmd.createRegion(regionPath, defaultRegionType, null, null, true, + null, null, null, null, null, null, null, null, false, false, true, false, false, + false, + true, null, null, null, null, null, null, null, null, null, null, null, null, null, + false, + null, null, null, null, null, null, null, null, null, null, null); r = cache.getRegion(regionPath); - if (result.getStatus() == Status.ERROR && r == null) { + if (resultModel.getStatus() == Status.ERROR && r == null) { String err = "Unable to create region named \"" + regionPath + "\":\n"; - while (result.hasNextLine()) - err += result.nextLine(); - throw new RegionCreationException(err); + // TODO: check this + throw new RegionCreationException(err + resultModel.toJson()); } } while (r == null); // The region can be null in the case that it is concurrently destroyed by // a remote even triggered internally by Geode diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandTest.java index 4d68704..83ea16b 100644 --- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandTest.java +++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandTest.java @@ -172,31 +172,31 @@ public class CreateRegionCommandTest { assertThat(args.isIfNotExists()).isFalse(); assertThat(args.getKeyConstraint()).isNull(); assertThat(args.getValueConstraint()).isNull(); - assertThat(args.isStatisticsEnabled()).isNull(); + assertThat(args.getStatisticsEnabled()).isNull(); ExpirationAttrs empty = new ExpirationAttrs(null, null); - assertThat(args.getEntryExpirationIdleTime()).isEqualTo(empty); - assertThat(args.getEntryExpirationTTL()).isEqualTo(empty); - assertThat(args.getRegionExpirationIdleTime()).isEqualTo(empty); - assertThat(args.getRegionExpirationTTL()).isEqualTo(empty); + assertThat(args.getEntryExpirationIdleTime()).isNull(); + assertThat(args.getEntryExpirationTTL()).isNull(); + assertThat(args.getRegionExpirationIdleTime()).isNull(); + assertThat(args.getRegionExpirationTTL()).isNull(); assertThat(args.getDiskStore()).isNull(); - assertThat(args.isDiskSynchronous()).isNull(); - assertThat(args.isEnableAsyncConflation()).isNull(); - assertThat(args.isEnableSubscriptionConflation()).isNull(); + assertThat(args.getDiskSynchronous()).isNull(); + assertThat(args.getEnableAsyncConflation()).isNull(); + assertThat(args.getEnableSubscriptionConflation()).isNull(); assertThat(args.getCacheListeners()).isEmpty(); assertThat(args.getCacheLoader()).isNull(); assertThat(args.getCacheWriter()).isNull(); assertThat(args.getAsyncEventQueueIds()).isEmpty(); assertThat(args.getGatewaySenderIds()).isEmpty(); - assertThat(args.isConcurrencyChecksEnabled()).isNull(); - assertThat(args.isCloningEnabled()).isNull(); - assertThat(args.isMcastEnabled()).isNull(); + assertThat(args.getConcurrencyChecksEnabled()).isNull(); + assertThat(args.getCloningEnabled()).isNull(); + assertThat(args.getMcastEnabled()).isNull(); assertThat(args.getConcurrencyLevel()).isNull(); - assertThat(args.getPartitionArgs()).isNotNull(); + assertThat(args.getPartitionArgs()).isNull(); assertThat(args.getEvictionMax()).isNull(); assertThat(args.getCompressor()).isNull(); - assertThat(args.isOffHeap()).isNull(); + assertThat(args.getOffHeap()).isNull(); assertThat(args.getRegionAttributes()).isNull(); } diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java new file mode 100644 index 0000000..31b5bd9 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java @@ -0,0 +1,273 @@ +/* + * 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.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import org.apache.geode.cache.EvictionAction; +import org.apache.geode.cache.ExpirationAction; +import org.apache.geode.cache.configuration.ClassNameType; +import org.apache.geode.cache.configuration.DeclarableType; +import org.apache.geode.cache.configuration.EnumActionDestroyOverflow; +import org.apache.geode.cache.configuration.RegionAttributesType; +import org.apache.geode.cache.configuration.RegionConfig; +import org.apache.geode.management.internal.cli.functions.RegionFunctionArgs; + +public class RegionConfigFactoryTest { + + RegionConfigFactory subject; + RegionFunctionArgs args; + + @Before + public void setup() { + subject = new RegionConfigFactory(); + args = new RegionFunctionArgs(); + args.setRegionPath("region-name"); + } + + @Test + public void generatesConfigForRegion() { + RegionConfig config = subject.generate(args); + assertThat(config.getName()).isEqualTo("region-name"); + } + + @Test + public void generatesConfigForSubRegion() { + args.setRegionPath("region-name/subregion"); + + RegionConfig config = subject.generate(args); + assertThat(config.getName()).isEqualTo("subregion"); + } + + @Test + public void generatesWithNoAttributes() { + RegionConfig config = subject.generate(args); + assertThat(config.getRegionAttributes()).isEmpty(); + } + + @Test + public void generatesWithConstraintAttributes() { + args.setKeyConstraint("key-const"); + args.setValueConstraint("value-const"); + + RegionConfig config = subject.generate(args); + assertThat(getRegionAttributeValue(config, t -> t.getKeyConstraint())).isEqualTo("key-const"); + assertThat(getRegionAttributeValue(config, t -> t.getValueConstraint())) + .isEqualTo("value-const"); + } + + @Test + public void generatesWithExpirationIdleTimeAttributes() { + args.setRegionExpirationTTL(10, ExpirationAction.DESTROY); + args.setRegionExpirationIdleTime(3, ExpirationAction.INVALIDATE); + args.setEntryExpirationTTL(1, ExpirationAction.LOCAL_DESTROY); + args.setEntryExpirationIdleTime(12, ExpirationAction.LOCAL_DESTROY); + args.setEntryIdleTimeCustomExpiry(new ClassName<>("java.lang.String")); + + RegionConfig config = subject.generate(args); + RegionAttributesType.RegionTimeToLive regionTimeToLive = + (RegionAttributesType.RegionTimeToLive) getRegionAttributeValue(config, + t -> t.getRegionTimeToLive()); + assertThat(regionTimeToLive.getExpirationAttributes().getTimeout()).isEqualTo("10"); + + RegionAttributesType.EntryTimeToLive entryTimeToLive = + (RegionAttributesType.EntryTimeToLive) getRegionAttributeValue(config, + t -> t.getEntryTimeToLive()); + assertThat(entryTimeToLive.getExpirationAttributes().getAction()) + .isEqualTo(ExpirationAction.LOCAL_DESTROY.toXmlString()); + + RegionAttributesType.EntryIdleTime entryIdleTime = + (RegionAttributesType.EntryIdleTime) getRegionAttributeValue(config, + t -> t.getEntryIdleTime()); + DeclarableType customExpiry = entryIdleTime.getExpirationAttributes().getCustomExpiry(); + assertThat(customExpiry.getClassName()).isEqualTo("java.lang.String"); + assertThat(entryIdleTime.getExpirationAttributes().getAction()) + .isEqualTo(ExpirationAction.LOCAL_DESTROY.toXmlString()); + assertThat(entryIdleTime.getExpirationAttributes().getTimeout()) + .isEqualTo("12"); + } + + @Test + public void generatesWithDiskAttributes() { + args.setDiskStore("disk-store"); + args.setDiskSynchronous(false); + + RegionConfig config = subject.generate(args); + assertThat(getRegionAttributeValue(config, t -> t.getDiskStoreName())).isEqualTo("disk-store"); + assertThat(getRegionAttributeValue(config, t -> t.isDiskSynchronous())).isEqualTo(false); + } + + @Test + public void generatesWithPrAttributes() { + args.setPartitionArgs("colo-with", 100, + 100L, 100, 100L, + 100L, 100, "java.lang.String"); + + RegionConfig config = subject.generate(args); + RegionAttributesType.PartitionAttributes partitionAttributes = + (RegionAttributesType.PartitionAttributes) getRegionAttributeValue(config, + t -> t.getPartitionAttributes()); + assertThat(partitionAttributes).isNotNull(); + assertThat(partitionAttributes.getColocatedWith()).isEqualTo("colo-with"); + assertThat(partitionAttributes.getLocalMaxMemory()).isEqualTo("100"); + assertThat(partitionAttributes.getRecoveryDelay()).isEqualTo("100"); + assertThat(partitionAttributes.getRedundantCopies()).isEqualTo("100"); + assertThat(partitionAttributes.getStartupRecoveryDelay()).isEqualTo("100"); + assertThat(partitionAttributes.getTotalMaxMemory()).isEqualTo("100"); + assertThat(partitionAttributes.getTotalNumBuckets()).isEqualTo("100"); + + DeclarableType partitionResolverType = partitionAttributes.getPartitionResolver(); + assertThat(partitionResolverType.getClassName()).isEqualTo("java.lang.String"); + } + + @Test + public void generatesWithMiscBooleanFlags() { + args.setStatisticsEnabled(false); + args.setEnableAsyncConflation(false); + args.setConcurrencyChecksEnabled(true); + args.setEnableSubscriptionConflation(true); + args.setMcastEnabled(false); + args.setCloningEnabled(false); + args.setOffHeap(true); + RegionConfig config = subject.generate(args); + + assertThat(getRegionAttributeValue(config, t -> t.isStatisticsEnabled())).isEqualTo(false); + assertThat(getRegionAttributeValue(config, t -> t.isEnableSubscriptionConflation())) + .isEqualTo(true); + assertThat(getRegionAttributeValue(config, t -> t.isConcurrencyChecksEnabled())) + .isEqualTo(true); + assertThat(getRegionAttributeValue(config, t -> t.isEnableSubscriptionConflation())) + .isEqualTo(true); + assertThat(getRegionAttributeValue(config, t -> t.isMulticastEnabled())) + .isEqualTo(false); + assertThat(getRegionAttributeValue(config, t -> t.isCloningEnabled())).isEqualTo(false); + assertThat(getRegionAttributeValue(config, t -> t.isOffHeap())).isEqualTo(true); + } + + @Test + public void generatesWithGatewayFlags() { + args.setGatewaySenderIds(new String[] {"some-id", "some-other-id"}); + RegionConfig config = subject.generate(args); + + assertThat((String) getRegionAttributeValue(config, t -> t.getGatewaySenderIds())) + .contains("some-id"); + assertThat((String) getRegionAttributeValue(config, t -> t.getGatewaySenderIds())) + .contains("some-other-id"); + } + + @Test + public void generatesWithEvictionHeapPercentageFlags() { + args.setEvictionAttributes(EvictionAction.LOCAL_DESTROY.toString(), null, null, + "java.lang.String"); + RegionConfig config = subject.generate(args); + + RegionAttributesType.EvictionAttributes evictionAttributes = + (RegionAttributesType.EvictionAttributes) getRegionAttributeValue(config, + t -> t.getEvictionAttributes()); + assertThat(evictionAttributes).isNotNull(); + assertThat(evictionAttributes.getLruHeapPercentage().getAction()) + .isSameAs(EnumActionDestroyOverflow.LOCAL_DESTROY); + assertThat(evictionAttributes.getLruHeapPercentage().getClassName()) + .isEqualTo("java.lang.String"); + } + + @Test + public void generatesWithEvictionMaxMemory() { + args.setEvictionAttributes(EvictionAction.LOCAL_DESTROY.toString(), 100, null, + null); + RegionConfig config = subject.generate(args); + + RegionAttributesType.EvictionAttributes evictionAttributes = + (RegionAttributesType.EvictionAttributes) getRegionAttributeValue(config, + t -> t.getEvictionAttributes()); + assertThat(evictionAttributes).isNotNull(); + assertThat(evictionAttributes.getLruMemorySize().getAction()) + .isSameAs(EnumActionDestroyOverflow.LOCAL_DESTROY); + assertThat(evictionAttributes.getLruMemorySize().getMaximum()).isEqualTo("100"); + } + + @Test + public void generatesWithEvictionMaxEntry() { + args.setEvictionAttributes(EvictionAction.OVERFLOW_TO_DISK.toString(), null, 1, + null); + RegionConfig config = subject.generate(args); + RegionAttributesType.EvictionAttributes evictionAttributes = + (RegionAttributesType.EvictionAttributes) getRegionAttributeValue(config, + t -> t.getEvictionAttributes()); + assertThat(evictionAttributes).isNotNull(); + assertThat(evictionAttributes.getLruEntryCount().getAction()) + .isSameAs(EnumActionDestroyOverflow.OVERFLOW_TO_DISK); + assertThat(evictionAttributes.getLruEntryCount().getMaximum()).isEqualTo("1"); + } + + @Test + public void generatesWithAsyncEventQueueIds() { + args.setAsyncEventQueueIds(new String[] {"id-1", "id-2"}); + RegionConfig config = subject.generate(args); + + assertThat((String) getRegionAttributeValue(config, t -> t.getAsyncEventQueueIds())) + .contains("id-1"); + assertThat((String) getRegionAttributeValue(config, t -> t.getAsyncEventQueueIds())) + .contains("id-2"); + } + + @Test + public void generatesWithCacheClasses() { + args.setCacheListeners(new ClassName[] {new ClassName("java.lang.String")}); + args.setCacheLoader(new ClassName("java.lang.String")); + args.setCacheWriter(new ClassName("java.lang.String")); + RegionConfig config = subject.generate(args); + + List<DeclarableType> cacheListeners = config.getRegionAttributes().stream() + .filter(a -> !a.getCacheListeners().isEmpty()) + .findFirst() + .map(a -> a.getCacheListeners()) + .orElse(null); + + assertThat(cacheListeners).isNotNull(); + assertThat(cacheListeners.get(0).getClassName()).isEqualTo("java.lang.String"); + assertThat( + ((DeclarableType) getRegionAttributeValue(config, t -> t.getCacheLoader())).getClassName()) + .isEqualTo("java.lang.String"); + assertThat( + ((DeclarableType) getRegionAttributeValue(config, t -> t.getCacheWriter())).getClassName()) + .isEqualTo("java.lang.String"); + } + + @Test + public void generatesWithOtherMiscSimpleFlags() { + args.setCompressor("java.lang.String"); + args.setConcurrencyLevel(1); + + RegionConfig config = subject.generate(args); + + assertThat( + ((ClassNameType) getRegionAttributeValue(config, t -> t.getCompressor())).getClassName()) + .isEqualTo("java.lang.String"); + assertThat(getRegionAttributeValue(config, t -> t.getConcurrencyLevel())).isEqualTo("1"); + } + + private Object getRegionAttributeValue(RegionConfig config, RegionAttributeGetFunction function) { + return config.getRegionAttributes().stream() + .findFirst() + .map(a -> function.getValue(a)) + .orElse(null); + } +} diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgsTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgsTest.java index de22efb..12d6dd5 100644 --- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgsTest.java +++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgsTest.java @@ -37,16 +37,40 @@ public class RegionFunctionArgsTest { @Test public void defaultRegionFunctionArgs() throws Exception { - assertThat(args.isDiskSynchronous()).isNull(); - assertThat(args.isCloningEnabled()).isNull(); - assertThat(args.isConcurrencyChecksEnabled()).isNull(); + assertThat(args.getDiskSynchronous()).isNull(); + assertThat(args.getCloningEnabled()).isNull(); + assertThat(args.getConcurrencyChecksEnabled()).isNull(); assertThat(args.getConcurrencyLevel()).isNull(); - assertThat(args.getPartitionArgs()).isNotNull(); - assertThat(args.getPartitionArgs().hasPartitionAttributes()).isFalse(); + assertThat(args.getPartitionArgs()).isNull(); + assertThat(args.hasPartitionAttributes()).isFalse(); assertThat(args.getEvictionAttributes()).isNull(); } @Test + public void emptyPartitionArgsShouldBeNull() throws Exception { + args.setPartitionArgs(null, null, null, + null, null, null, + null, null); + assertThat(args.getPartitionArgs()).isNull(); + assertThat(args.hasPartitionAttributes()).isFalse(); + } + + @Test + public void emptyExpirationAttributesShouldBeNull() throws Exception { + args.setEntryExpirationIdleTime(null, null); + assertThat(args.getEntryExpirationIdleTime()).isNull(); + + args.setEntryExpirationTTL(null, null); + assertThat(args.getEntryExpirationTTL()).isNull(); + + args.setRegionExpirationIdleTime(null, null); + assertThat(args.getRegionExpirationIdleTime()).isNull(); + + args.setRegionExpirationTTL(null, null); + assertThat(args.getRegionExpirationTTL()).isNull(); + } + + @Test public void defaultPartitionArgs() throws Exception { assertThat(partitionArgs.hasPartitionAttributes()).isFalse(); @@ -64,19 +88,22 @@ public class RegionFunctionArgsTest { assertThat(args.getEvictionAttributes()).isNull(); args.setEvictionAttributes("local-destroy", null, null, null); - EvictionAttributes attributes = args.getEvictionAttributes(); + EvictionAttributes attributes = args.getEvictionAttributes() + .convertToEvictionAttributes(); assertThat(attributes.getAlgorithm()).isEqualTo(EvictionAlgorithm.LRU_HEAP); assertThat(attributes.getAction()).isEqualTo(EvictionAction.LOCAL_DESTROY); assertThat(attributes.getMaximum()).isEqualTo(0); args.setEvictionAttributes("overflow-to-disk", 1000, null, null); - EvictionAttributes attributes1 = args.getEvictionAttributes(); + EvictionAttributes attributes1 = args.getEvictionAttributes() + .convertToEvictionAttributes(); assertThat(attributes1.getAlgorithm()).isEqualTo(EvictionAlgorithm.LRU_MEMORY); assertThat(attributes1.getAction()).isEqualTo(EvictionAction.OVERFLOW_TO_DISK); assertThat(attributes1.getMaximum()).isEqualTo(1000); args.setEvictionAttributes("local-destroy", null, 1000, null); - EvictionAttributes attributes2 = args.getEvictionAttributes(); + EvictionAttributes attributes2 = args.getEvictionAttributes() + .convertToEvictionAttributes(); assertThat(attributes2.getAlgorithm()).isEqualTo(EvictionAlgorithm.LRU_ENTRY); assertThat(attributes2.getAction()).isEqualTo(EvictionAction.LOCAL_DESTROY); assertThat(attributes2.getMaximum()).isEqualTo(1000); @@ -85,7 +112,7 @@ public class RegionFunctionArgsTest { @Test public void evictionAttributesWithNullAction() throws Exception { args.setEvictionAttributes(null, null, 1000, null); - EvictionAttributes attributes3 = args.getEvictionAttributes(); + RegionFunctionArgs.EvictionAttrs attributes3 = args.getEvictionAttributes(); assertThat(attributes3).isNull(); } } diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java index 365eb73..57d91a3 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java @@ -14,13 +14,17 @@ */ package org.apache.geode.management.internal.cli.commands; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TestName; +import org.apache.geode.cache.Region; import org.apache.geode.test.dunit.IgnoredException; import org.apache.geode.test.dunit.rules.ClusterStartupRule; import org.apache.geode.test.dunit.rules.MemberVM; @@ -65,9 +69,9 @@ public class CreateRegionCommandDUnitTest { + " --async-event-queue-id=" + asyncQueueName) .statusIsError() .containsOutput("server-1", - "ERROR: Parallel Async Event Queue " + asyncQueueName + "Parallel Async Event Queue " + asyncQueueName + " can not be used with replicated region /" + regionName) - .containsOutput("server-2", "ERROR: Parallel Async Event Queue " + asyncQueueName + .containsOutput("server-2", "Parallel Async Event Queue " + asyncQueueName + " can not be used with replicated region /" + regionName); // The exception must be thrown early in the initialization, so the region itself shouldn't be @@ -91,13 +95,56 @@ public class CreateRegionCommandDUnitTest { + " --gateway-sender-id=" + gatewaySenderName) .statusIsError() .containsOutput("server-1", - "ERROR: Parallel gateway sender " + gatewaySenderName + "Parallel gateway sender " + gatewaySenderName + " can not be used with replicated region /" + regionName) - .containsOutput("server-2", "ERROR: Parallel gateway sender " + gatewaySenderName + .containsOutput("server-2", "Parallel gateway sender " + gatewaySenderName + " can not be used with replicated region /" + regionName); // The exception must be thrown early in the initialization, so the region itself shouldn't be // added to the root regions. gfsh.executeAndAssertThat("list regions").statusIsSuccess().doesNotContainOutput(regionName); } + + /** + * Ignored this test until we refactor the FetchRegionAttributesFunction to not use + * AttributesFactory, and instead use RegionConfig, which we will do as part of implementing + * GEODE-6103 + */ + @Ignore + @Test + public void createRegionFromTemplateWithGatewaySender() throws Exception { + String regionName = testName.getMethodName(); + String sender = "sender1"; + String remoteDS = "2"; + IgnoredException.addIgnoredException("could not get remote locator information"); + + gfsh.executeAndAssertThat("create gateway-sender" + + " --id=" + sender + + " --remote-distributed-system-id=" + remoteDS).statusIsSuccess(); + + // Give gateway sender time to get created + Thread.sleep(2000); + + gfsh.executeAndAssertThat("create region" + + " --name=" + regionName + + " --type=REPLICATE_PERSISTENT" + + " --gateway-sender-id=" + sender).statusIsSuccess(); + + String regionNameFromTemplate = regionName + "-from-template"; + gfsh.executeAndAssertThat("create region --name=" + regionNameFromTemplate + + " --template-region=" + regionName) + .statusIsSuccess(); + + server1.invoke(() -> { + Region region1 = ClusterStartupRule.getCache().getRegion(regionNameFromTemplate); + assertThat(region1.getAttributes().getGatewaySenderIds()) + .describedAs("region1 contains gateway sender") + .contains(sender); + + Region region2 = ClusterStartupRule.getCache().getRegion(regionNameFromTemplate); + assertThat(region2.getAttributes().getGatewaySenderIds()) + .describedAs("region2 contains gateway sender") + .contains(sender); + }); + } }
