GEODE-8748: Prevents NPE on alter expiry on proxy regions (#5790)

        * When a region is created with zero local memory, there is no bucket regions created.
	* When alter region is called on this proxy region to alter expiry, it tries to manipulate the bucket region.
	* But there are no buckets and hence NPE is thrown.
	* In this commit a null check is done before alter the bucket regions.
	* Configs still need to changed to prevent restart issues.
	* This similar to the check done in setEntryTimeToLive in PartitionedRegion class
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegion.java b/geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegion.java
index ebc778a..afafb8b 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegion.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegion.java
@@ -9362,8 +9362,10 @@
      * updatePRConfig(...) to make changes that cause bucket creation to live lock
      */
     PartitionRegionHelper.assignBucketsToPartitions(this);
-    dataStore.lockBucketCreationAndVisit(
-        (bucketId, r) -> r.getAttributesMutator().setEntryTimeToLive(timeToLive));
+    if (dataStore != null) {
+      dataStore.lockBucketCreationAndVisit(
+          (bucketId, r) -> r.getAttributesMutator().setEntryTimeToLive(timeToLive));
+    }
     updatePartitionRegionConfig(config -> config.setEntryTimeToLive(timeToLive));
     return attr;
   }
@@ -9378,8 +9380,10 @@
   public CustomExpiry setCustomEntryTimeToLive(CustomExpiry custom) {
     CustomExpiry expiry = super.setCustomEntryTimeToLive(custom);
     // Set to Bucket regions as well
-    dataStore.lockBucketCreationAndVisit(
-        (bucketId, r) -> r.getAttributesMutator().setCustomEntryTimeToLive(custom));
+    if (dataStore != null) {
+      dataStore.lockBucketCreationAndVisit(
+          (bucketId, r) -> r.getAttributesMutator().setCustomEntryTimeToLive(custom));
+    }
     return expiry;
   }
 
@@ -9404,9 +9408,10 @@
      */
     PartitionRegionHelper.assignBucketsToPartitions(this);
     // Set to Bucket regions as well
-    dataStore.lockBucketCreationAndVisit(
-        (bucketId, r) -> r.getAttributesMutator().setEntryIdleTimeout(idleTimeout));
-
+    if (dataStore != null) {
+      dataStore.lockBucketCreationAndVisit(
+          (bucketId, r) -> r.getAttributesMutator().setEntryIdleTimeout(idleTimeout));
+    }
     updatePartitionRegionConfig(config -> config.setEntryIdleTimeout(idleTimeout));
     return attr;
   }
@@ -9421,8 +9426,10 @@
   public CustomExpiry setCustomEntryIdleTimeout(CustomExpiry custom) {
     CustomExpiry expiry = super.setCustomEntryIdleTimeout(custom);
     // Set to Bucket regions as well
-    dataStore.lockBucketCreationAndVisit(
-        (bucketId, r) -> r.getAttributesMutator().setCustomEntryIdleTimeout(custom));
+    if (dataStore != null) {
+      dataStore.lockBucketCreationAndVisit(
+          (bucketId, r) -> r.getAttributesMutator().setCustomEntryIdleTimeout(custom));
+    }
     return expiry;
   }
 
diff --git a/geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/AlterTimeToLiveExpirationOnProxyRegionDUnitTest.java b/geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/AlterTimeToLiveExpirationOnProxyRegionDUnitTest.java
new file mode 100644
index 0000000..a451c4f
--- /dev/null
+++ b/geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/AlterTimeToLiveExpirationOnProxyRegionDUnitTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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 junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.categories.EvictionTest;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+@Category({EvictionTest.class})
+@RunWith(JUnitParamsRunner.class)
+public class AlterTimeToLiveExpirationOnProxyRegionDUnitTest {
+  @Rule
+  public ClusterStartupRule clusterStartupRule = new ClusterStartupRule();
+  @Rule
+  public GfshCommandRule gfsh = new GfshCommandRule();
+
+  public Object[] getRegionTypePairs() {
+    return new Object[] {
+        new Object[] {"REPLICATE", "REPLICATE_PROXY"},
+        new Object[] {"PARTITION", "PARTITION_PROXY"},
+        new Object[] {"PARTITION_REDUNDANT", "PARTITION_PROXY_REDUNDANT"}
+    };
+  }
+
+  @Test
+  @Parameters(method = "getRegionTypePairs")
+  @TestCaseName("[{index}] {method} Non Proxy Region Type:{0}; Proxy Region Type:{1}")
+  public void whenExpirationIsSetUsingAlterOnProxyRegionThenItShouldNotThrowException(
+      String nonProxyRegionType, String proxyRegionType) throws Exception {
+    MemberVM locator = clusterStartupRule.startLocatorVM(0);
+    MemberVM server1 = clusterStartupRule.startServerVM(1, "non-proxy", locator.getPort());
+    MemberVM server2 = clusterStartupRule.startServerVM(2, "proxy", locator.getPort());
+    gfsh.connectAndVerify(locator);
+
+    gfsh.executeAndAssertThat(
+        "create region --name=region --type=" + nonProxyRegionType
+            + " --enable-statistics=true --group=non-proxy")
+        .statusIsSuccess();
+    gfsh.executeAndAssertThat(
+        "create region --name=region --type=" + proxyRegionType
+            + " --enable-statistics=true --group=proxy")
+        .statusIsSuccess();
+
+    gfsh.executeAndAssertThat(
+        "alter region --name=region --entry-time-to-live-expiration=1000 --entry-time-to-live-expiration-action=destroy --group=non-proxy")
+        .statusIsSuccess();
+    gfsh.executeAndAssertThat(
+        "alter region --name=region --entry-time-to-live-expiration=1000 --entry-time-to-live-expiration-action=destroy --group=proxy")
+        .statusIsSuccess();
+
+  }
+
+}