forked from apolloconfig/apollo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
unlock namespace when is redo operation
- Loading branch information
Showing
5 changed files
with
268 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
147 changes: 147 additions & 0 deletions
147
...vice/src/main/java/com/ctrip/framework/apollo/adminservice/aop/NamespaceUnlockAspect.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package com.ctrip.framework.apollo.adminservice.aop; | ||
|
||
|
||
import com.google.common.collect.Maps; | ||
import com.google.gson.Gson; | ||
|
||
import com.ctrip.framework.apollo.biz.config.BizConfig; | ||
import com.ctrip.framework.apollo.biz.entity.Item; | ||
import com.ctrip.framework.apollo.biz.entity.Namespace; | ||
import com.ctrip.framework.apollo.biz.entity.Release; | ||
import com.ctrip.framework.apollo.biz.service.ItemService; | ||
import com.ctrip.framework.apollo.biz.service.NamespaceLockService; | ||
import com.ctrip.framework.apollo.biz.service.NamespaceService; | ||
import com.ctrip.framework.apollo.biz.service.ReleaseService; | ||
import com.ctrip.framework.apollo.common.constants.GsonType; | ||
import com.ctrip.framework.apollo.common.dto.ItemChangeSets; | ||
import com.ctrip.framework.apollo.common.dto.ItemDTO; | ||
import com.ctrip.framework.apollo.common.exception.BadRequestException; | ||
import com.ctrip.framework.apollo.core.utils.StringUtils; | ||
|
||
import org.aspectj.lang.annotation.After; | ||
import org.aspectj.lang.annotation.Aspect; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
|
||
/** | ||
* unlock namespace if is redo operation. | ||
* -------------------------------------------- | ||
* For example: If namespace has a item K1 = v1 | ||
* -------------------------------------------- | ||
* First operate: change k1 = v2 (lock namespace) | ||
* Second operate: change k1 = v1 (unlock namespace) | ||
* | ||
*/ | ||
@Aspect | ||
@Component | ||
public class NamespaceUnlockAspect { | ||
|
||
private Gson gson = new Gson(); | ||
|
||
@Autowired | ||
private NamespaceLockService namespaceLockService; | ||
@Autowired | ||
private NamespaceService namespaceService; | ||
@Autowired | ||
private ItemService itemService; | ||
@Autowired | ||
private ReleaseService releaseService; | ||
@Autowired | ||
private BizConfig bizConfig; | ||
|
||
|
||
//create item | ||
@After("@annotation(PreAcquireNamespaceLock) && args(appId, clusterName, namespaceName, item, ..)") | ||
public void requireLockAdvice(String appId, String clusterName, String namespaceName, | ||
ItemDTO item) { | ||
tryUnlock(namespaceService.findOne(appId, clusterName, namespaceName)); | ||
} | ||
|
||
//update item | ||
@After("@annotation(PreAcquireNamespaceLock) && args(appId, clusterName, namespaceName, itemId, item, ..)") | ||
public void requireLockAdvice(String appId, String clusterName, String namespaceName, long itemId, | ||
ItemDTO item) { | ||
tryUnlock(namespaceService.findOne(appId, clusterName, namespaceName)); | ||
} | ||
|
||
//update by change set | ||
@After("@annotation(PreAcquireNamespaceLock) && args(appId, clusterName, namespaceName, changeSet, ..)") | ||
public void requireLockAdvice(String appId, String clusterName, String namespaceName, | ||
ItemChangeSets changeSet) { | ||
tryUnlock(namespaceService.findOne(appId, clusterName, namespaceName)); | ||
} | ||
|
||
//delete item | ||
@After("@annotation(PreAcquireNamespaceLock) && args(itemId, operator, ..)") | ||
public void requireLockAdvice(long itemId, String operator) { | ||
Item item = itemService.findOne(itemId); | ||
if (item == null) { | ||
throw new BadRequestException("item not exist."); | ||
} | ||
tryUnlock(namespaceService.findOne(item.getNamespaceId())); | ||
} | ||
|
||
private void tryUnlock(Namespace namespace) { | ||
if (bizConfig.isNamespaceLockSwitchOff()) { | ||
return; | ||
} | ||
|
||
if (!isModified(namespace)) { | ||
namespaceLockService.unlock(namespace.getId()); | ||
} | ||
|
||
} | ||
|
||
boolean isModified(Namespace namespace) { | ||
Release release = releaseService.findLatestActiveRelease(namespace); | ||
List<Item> items = itemService.findItems(namespace.getId()); | ||
|
||
if (release == null) { | ||
return hasNormalItems(items); | ||
} | ||
|
||
Map<String, String> releasedConfiguration = gson.fromJson(release.getConfigurations(), GsonType.CONFIG); | ||
Map<String, String> configurationFromItems = Maps.newHashMap(); | ||
|
||
for (Item item : items) { | ||
String key = item.getKey(); | ||
if (StringUtils.isBlank(key)) { | ||
continue; | ||
} | ||
//added | ||
if (releasedConfiguration.get(key) == null) { | ||
return true; | ||
} | ||
configurationFromItems.put(key, item.getValue()); | ||
} | ||
|
||
for (Map.Entry<String, String> entry : releasedConfiguration.entrySet()) { | ||
String key = entry.getKey(); | ||
String value = entry.getValue(); | ||
|
||
//deleted or modified | ||
if (!Objects.equals(configurationFromItems.get(key), value)) { | ||
return true; | ||
} | ||
|
||
} | ||
|
||
return false; | ||
} | ||
|
||
private boolean hasNormalItems(List<Item> items) { | ||
for (Item item : items) { | ||
if (!StringUtils.isEmpty(item.getKey())) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
.../src/test/java/com/ctrip/framework/apollo/adminservice/aop/NamespaceUnlockAspectTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package com.ctrip.framework.apollo.adminservice.aop; | ||
|
||
import com.ctrip.framework.apollo.biz.entity.Item; | ||
import com.ctrip.framework.apollo.biz.entity.Namespace; | ||
import com.ctrip.framework.apollo.biz.entity.Release; | ||
import com.ctrip.framework.apollo.biz.service.ItemService; | ||
import com.ctrip.framework.apollo.biz.service.ReleaseService; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.runners.MockitoJUnitRunner; | ||
|
||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import static org.mockito.Mockito.when; | ||
|
||
@RunWith(MockitoJUnitRunner.class) | ||
public class NamespaceUnlockAspectTest { | ||
|
||
@Mock | ||
private ReleaseService releaseService; | ||
@Mock | ||
private ItemService itemService; | ||
|
||
@InjectMocks | ||
private NamespaceUnlockAspect namespaceUnlockAspect; | ||
|
||
|
||
@Test | ||
public void testNamespaceHasNoNormalItemsAndRelease() { | ||
|
||
long namespaceId = 1; | ||
Namespace namespace = createNamespace(namespaceId); | ||
|
||
when(releaseService.findLatestActiveRelease(namespace)).thenReturn(null); | ||
when(itemService.findItems(namespaceId)).thenReturn(Collections.singletonList(createItem("", ""))); | ||
|
||
boolean isModified = namespaceUnlockAspect.isModified(namespace); | ||
|
||
Assert.assertFalse(isModified); | ||
} | ||
|
||
@Test | ||
public void testNamespaceAddItem() { | ||
long namespaceId = 1; | ||
Namespace namespace = createNamespace(namespaceId); | ||
|
||
Release release = createRelease("{\"k1\":\"v1\"}"); | ||
List<Item> items = Arrays.asList(createItem("k1", "v1"), createItem("k2", "v2")); | ||
|
||
when(releaseService.findLatestActiveRelease(namespace)).thenReturn(release); | ||
when(itemService.findItems(namespaceId)).thenReturn(items); | ||
|
||
boolean isModified = namespaceUnlockAspect.isModified(namespace); | ||
|
||
Assert.assertTrue(isModified); | ||
} | ||
|
||
@Test | ||
public void testNamespaceModifyItem() { | ||
long namespaceId = 1; | ||
Namespace namespace = createNamespace(namespaceId); | ||
|
||
Release release = createRelease("{\"k1\":\"v1\"}"); | ||
List<Item> items = Arrays.asList(createItem("k1", "v2")); | ||
|
||
when(releaseService.findLatestActiveRelease(namespace)).thenReturn(release); | ||
when(itemService.findItems(namespaceId)).thenReturn(items); | ||
|
||
boolean isModified = namespaceUnlockAspect.isModified(namespace); | ||
|
||
Assert.assertTrue(isModified); | ||
} | ||
|
||
@Test | ||
public void testNamespaceDeleteItem() { | ||
long namespaceId = 1; | ||
Namespace namespace = createNamespace(namespaceId); | ||
|
||
Release release = createRelease("{\"k1\":\"v1\"}"); | ||
List<Item> items = Arrays.asList(createItem("k2", "v2")); | ||
|
||
when(releaseService.findLatestActiveRelease(namespace)).thenReturn(release); | ||
when(itemService.findItems(namespaceId)).thenReturn(items); | ||
|
||
boolean isModified = namespaceUnlockAspect.isModified(namespace); | ||
|
||
Assert.assertTrue(isModified); | ||
} | ||
|
||
private Namespace createNamespace(long namespaceId) { | ||
Namespace namespace = new Namespace(); | ||
namespace.setId(namespaceId); | ||
return namespace; | ||
} | ||
|
||
private Item createItem(String key, String value) { | ||
Item item = new Item(); | ||
item.setKey(key); | ||
item.setValue(value); | ||
return item; | ||
} | ||
|
||
private Release createRelease(String configuration) { | ||
Release release = new Release(); | ||
release.setConfigurations(configuration); | ||
return release; | ||
} | ||
|
||
} |