RegionAlterFunction extends CliFunction<RegionConfig> { void alterRegion(Cache cache, RegionConfig deltaConfig) { final String regionPathString = deltaConfig.getName(); AbstractRegion region = (AbstractRegion) cache.getRegion(regionPathString); if (region == null) { throw new IllegalArgumentException( String.format("Region does not exist: %s", regionPathString)); } @SuppressWarnings("unchecked") AttributesMutator<Object, Object> mutator = region.getAttributesMutator(); RegionAttributesType regionAttributes = deltaConfig.getRegionAttributes(); if (regionAttributes.isCloningEnabled() != null) { mutator.setCloningEnabled(regionAttributes.isCloningEnabled()); if (logger.isDebugEnabled()) { logger.debug("Region successfully altered - cloning"); } } if (regionAttributes.getEvictionAttributes() != null) { mutator.getEvictionAttributesMutator().setMaximum(Integer .parseInt(regionAttributes.getEvictionAttributes().getLruEntryCount().getMaximum())); if (logger.isDebugEnabled()) { logger.debug("Region successfully altered - eviction attributes max"); } } updateExpirationAttributes(cache, regionAttributes.getEntryIdleTime(), region.getEntryIdleTimeout(), mutator::setEntryIdleTimeout, mutator::setCustomEntryIdleTimeout); updateExpirationAttributes(cache, regionAttributes.getEntryTimeToLive(), region.getEntryTimeToLive(), mutator::setEntryTimeToLive, mutator::setCustomEntryTimeToLive); updateExpirationAttributes(cache, regionAttributes.getRegionIdleTime(), region.getRegionIdleTimeout(), mutator::setRegionIdleTimeout, null); updateExpirationAttributes(cache, regionAttributes.getRegionTimeToLive(), region.getRegionTimeToLive(), mutator::setRegionTimeToLive, null); final Set<String> newGatewaySenderIds = regionAttributes.getGatewaySenderIdsAsSet(); final Set<String> newAsyncEventQueueIds = regionAttributes.getAsyncEventQueueIdsAsSet(); if (region instanceof PartitionedRegion) { Set<String> senderIds = new HashSet<>(); if (newGatewaySenderIds != null) { validateParallelGatewaySenderIDs((PartitionedRegion) region, newGatewaySenderIds); senderIds.addAll(newGatewaySenderIds); } else if (region.getGatewaySenderIds() != null) { senderIds.addAll(region.getAllGatewaySenderIds()); } if (newAsyncEventQueueIds != null) { validateParallelAsynchronousEventQueueIDs((PartitionedRegion) region, newAsyncEventQueueIds); senderIds.addAll(newAsyncEventQueueIds); } else if (region.getAsyncEventQueueIds() != null) { senderIds.addAll(region.getAsyncEventQueueIds()); } ((PartitionedRegion) region) .updatePRConfigWithNewSetOfAsynchronousEventDispatchers(senderIds); } if (newGatewaySenderIds != null) { Set<String> oldGatewaySenderIds = region.getGatewaySenderIds(); oldGatewaySenderIds.stream().filter(not(newGatewaySenderIds::contains)) .forEach(mutator::removeGatewaySenderId); newGatewaySenderIds.stream().filter(not(oldGatewaySenderIds::contains)) .forEach(mutator::addGatewaySenderId); if (logger.isDebugEnabled()) { logger.debug("Region successfully altered - gateway sender IDs"); } } if (newAsyncEventQueueIds != null) { Set<String> oldAsyncEventQueueIds = region.getAsyncEventQueueIds(); oldAsyncEventQueueIds.stream().filter(not(newAsyncEventQueueIds::contains)) .forEach(mutator::removeAsyncEventQueueId); newAsyncEventQueueIds.stream().filter(not(oldAsyncEventQueueIds::contains)) .forEach(mutator::addAsyncEventQueueId); if (logger.isDebugEnabled()) { logger.debug("Region successfully altered - async event queue IDs"); } } final List<DeclarableType> newCacheListeners = regionAttributes.getCacheListeners(); if (!newCacheListeners.isEmpty()) { @SuppressWarnings("unchecked") CacheListener<Object, Object>[] oldCacheListeners = region.getCacheListeners(); for (CacheListener<Object, Object> oldCacheListener : oldCacheListeners) { mutator.removeCacheListener(oldCacheListener); } for (DeclarableType newCacheListener : newCacheListeners) { if (!newCacheListener.equals(DeclarableType.EMPTY)) { mutator.addCacheListener(DeclarableTypeInstantiator.newInstance(newCacheListener, cache)); } } if (logger.isDebugEnabled()) { logger.debug("Region successfully altered - cache listeners"); } } final DeclarableType cacheLoader = regionAttributes.getCacheLoader(); if (cacheLoader != null) { if (cacheLoader.equals(DeclarableType.EMPTY)) { mutator.setCacheLoader(null); } else { mutator.setCacheLoader(DeclarableTypeInstantiator.newInstance(cacheLoader, cache)); } if (logger.isDebugEnabled()) { logger.debug("Region successfully altered - cache loader"); } } final DeclarableType cacheWriter = regionAttributes.getCacheWriter(); if (cacheWriter != null) { if (cacheWriter.equals(DeclarableType.EMPTY)) { mutator.setCacheWriter(null); } else { mutator.setCacheWriter(DeclarableTypeInstantiator.newInstance(cacheWriter, cache)); } if (logger.isDebugEnabled()) { logger.debug("Region successfully altered - cache writer"); } } }  @Override boolean isHA(); @Override String getId(); @Override CliFunctionResult executeFunction(FunctionContext<RegionConfig> context);  }
@Test public void alterRegionWithNullRegionThrowsIllegalArgumentException() { when(cache.getRegion(anyString())).thenReturn(null); config.setName("regionA"); assertThatThrownBy(() -> function.alterRegion(cache, config)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Region does not exist: regionA"); }
@Test public void updateWithEmptyRegionAttributes() { function.alterRegion(cache, config); verifyNoMoreInteractions(mutator); }
@Test public void updateWithCloningEnabled() { regionAttributes.setCloningEnabled(false); function.alterRegion(cache, config); verify(mutator).setCloningEnabled(false); }
@Test public void updateWithEvictionAttributes() { RegionAttributesType.EvictionAttributes evictionAttributes = new RegionAttributesType.EvictionAttributes(); RegionAttributesType.EvictionAttributes.LruEntryCount lruEntryCount = new RegionAttributesType.EvictionAttributes.LruEntryCount(); lruEntryCount.setMaximum("10"); evictionAttributes.setLruEntryCount(lruEntryCount); regionAttributes.setEvictionAttributes(evictionAttributes); function.alterRegion(cache, config); verify(mutator).getEvictionAttributesMutator(); verify(evictionMutator).setMaximum(10); }
@Test public void updateWithEntryIdleTime_timeoutAndAction() { RegionAttributesType.ExpirationAttributesType expiration = new RegionAttributesType.ExpirationAttributesType(); regionAttributes.setEntryIdleTime(expiration); expiration.setTimeout("10"); expiration.setAction("invalidate"); ExpirationAttributes existing = new ExpirationAttributes(); when(region.getEntryIdleTimeout()).thenReturn(existing); function.alterRegion(cache, config); ArgumentCaptor<ExpirationAttributes> updatedCaptor = ArgumentCaptor.forClass(ExpirationAttributes.class); verify(mutator).setEntryIdleTimeout(updatedCaptor.capture()); assertThat(updatedCaptor.getValue().getTimeout()).isEqualTo(10); assertThat(updatedCaptor.getValue().getAction()).isEqualTo(ExpirationAction.INVALIDATE); verify(mutator, times(0)).setCustomEntryIdleTimeout(any()); }
@Test public void updateWithEntryIdleTime_TimeoutOnly() { RegionAttributesType.ExpirationAttributesType expiration = new RegionAttributesType.ExpirationAttributesType(); regionAttributes.setEntryIdleTime(expiration); expiration.setTimeout("10"); ExpirationAttributes existing = new ExpirationAttributes(20, ExpirationAction.DESTROY); when(region.getEntryIdleTimeout()).thenReturn(existing); function.alterRegion(cache, config); ArgumentCaptor<ExpirationAttributes> updatedCaptor = ArgumentCaptor.forClass(ExpirationAttributes.class); verify(mutator).setEntryIdleTimeout(updatedCaptor.capture()); assertThat(updatedCaptor.getValue().getTimeout()).isEqualTo(10); assertThat(updatedCaptor.getValue().getAction()).isEqualTo(ExpirationAction.DESTROY); verify(mutator, times(0)).setCustomEntryIdleTimeout(any()); }
@Test public void updateWithCustomExpiry() { RegionAttributesType.ExpirationAttributesType expiration = new RegionAttributesType.ExpirationAttributesType(); regionAttributes.setEntryIdleTime(expiration); DeclarableType mockExpiry = mock(DeclarableType.class); when(mockExpiry.getClassName()).thenReturn(MyCustomExpiry.class.getName()); expiration.setCustomExpiry(mockExpiry); function.alterRegion(cache, config); verify(mutator, times(0)).setEntryIdleTimeout(any()); verify(mutator).setCustomEntryIdleTimeout(notNull()); }
@Test public void deleteCustomExpiry() { RegionAttributesType.ExpirationAttributesType expiration = new RegionAttributesType.ExpirationAttributesType(); regionAttributes.setEntryIdleTime(expiration); expiration.setCustomExpiry(DeclarableType.EMPTY); function.alterRegion(cache, config); verify(mutator, times(0)).setEntryIdleTimeout(any()); verify(mutator).setCustomEntryIdleTimeout(null); }
@Test public void updateWithGatewaySenders() { regionAttributes.setGatewaySenderIds("2,3"); when(region.getGatewaySenderIds()).thenReturn(new HashSet<>(Arrays.asList("1", "2"))); function.alterRegion(cache, config); verify(mutator).removeGatewaySenderId("1"); verify(mutator, times(0)).removeGatewaySenderId("2"); verify(mutator).addGatewaySenderId("3"); verify(mutator, times(0)).addAsyncEventQueueId(any()); verify(mutator, times(0)).removeAsyncEventQueueId(any()); }
@Test public void updateWithEmptyGatewaySenders() { regionAttributes.setGatewaySenderIds(""); when(region.getGatewaySenderIds()).thenReturn(new HashSet<>(Arrays.asList("1", "2"))); function.alterRegion(cache, config); verify(mutator).removeGatewaySenderId("1"); verify(mutator).removeGatewaySenderId("2"); }
@Test public void updateWithAsynchronousEventQueues() { regionAttributes.setAsyncEventQueueIds("queue2,queue3"); when(region.getAsyncEventQueueIds()) .thenReturn(new HashSet<>(Arrays.asList("queue1", "queue2"))); function.alterRegion(cache, config); verify(mutator).removeAsyncEventQueueId("queue1"); verify(mutator, times(0)).removeAsyncEventQueueId("queue2"); verify(mutator).addAsyncEventQueueId("queue3"); verify(mutator, times(0)).addGatewaySenderId(any()); verify(mutator, times(0)).removeGatewaySenderId(any()); }
@Test public void updateWithEmptyAsynchronousEventQueues() { regionAttributes.setAsyncEventQueueIds(""); when(region.getAsyncEventQueueIds()) .thenReturn(new HashSet<>(Arrays.asList("queue1", "queue2"))); function.alterRegion(cache, config); verify(mutator).removeAsyncEventQueueId("queue1"); verify(mutator).removeAsyncEventQueueId("queue2"); }
@Test public void updateWithCacheListeners() { @SuppressWarnings("unchecked") CacheListener<Object, Object> oldOne = mock(CacheListener.class); when(region.getCacheListeners()).thenReturn(new CacheListener[] {oldOne}); DeclarableType newCacheListenerType = mock(DeclarableType.class); when(newCacheListenerType.getClassName()).thenReturn(MyCacheListener.class.getName()); regionAttributes.getCacheListeners().add(newCacheListenerType); @SuppressWarnings("unchecked") ArgumentCaptor<CacheListener<Object, Object>> argument = ArgumentCaptor.forClass(CacheListener.class); function.alterRegion(cache, config); verify(mutator).removeCacheListener(oldOne); verify(mutator).addCacheListener(argument.capture()); assertThat(argument.getValue()).isInstanceOf(MyCacheListener.class); }
@Test public void updateWithEmptyCacheListeners() { @SuppressWarnings("unchecked") CacheListener<Object, Object> oldOne = mock(CacheListener.class); when(region.getCacheListeners()).thenReturn(new CacheListener[] {oldOne}); regionAttributes.getCacheListeners().add(DeclarableType.EMPTY); function.alterRegion(cache, config); verify(mutator).removeCacheListener(oldOne); verify(mutator, times(0)).addCacheListener(any()); }
@Test public void updateWithCacheWriter() { DeclarableType newCacheWriterDeclarable = mock(DeclarableType.class); when(newCacheWriterDeclarable.getClassName()).thenReturn(MyCacheWriter.class.getName()); regionAttributes.setCacheWriter(newCacheWriterDeclarable); function.alterRegion(cache, config); verify(mutator).setCacheWriter(notNull()); verify(mutator, times(0)).setCacheLoader(any()); }
@Test public void updateWithNoCacheWriter() { regionAttributes.setCacheWriter(DeclarableType.EMPTY); function.alterRegion(cache, config); verify(mutator).setCacheWriter(null); verify(mutator, times(0)).setCacheLoader(any()); }