提交 00467579 编写于 作者: Y Yiming Liu

Merge pull request #93 from lepdou/portal

规范portal异常处理
......@@ -8,6 +8,7 @@ import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.dto.NamespaceDTO;
import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.exception.ServiceException;
import com.ctrip.apollo.core.utils.StringUtils;
import org.slf4j.Logger;
......@@ -145,8 +146,9 @@ public class AdminServiceAPI {
if (response != null && response.getStatusCode() == HttpStatus.OK){
return response.getBody();
}else {
logger.error("release fail.id:{}, env:{}, clusterName:{}, namespace:{},releaseBy{}",appId, env, clusterName, namespace, releaseBy);
return null;
logger.error("createRelease fail.id:{}, env:{}, clusterName:{}, namespace:{},releaseBy{}",
appId, env, clusterName, namespace, releaseBy);
throw new ServiceException("call create createRelease api error.");
}
}
}
......
......@@ -5,15 +5,12 @@ import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.exception.BadRequestException;
import com.ctrip.apollo.core.utils.StringUtils;
import com.ctrip.apollo.portal.entity.form.NamespaceModifyModel;
import com.ctrip.apollo.portal.entity.form.NamespaceTextModel;
import com.ctrip.apollo.portal.entity.NamespaceVO;
import com.ctrip.apollo.portal.entity.SimpleMsg;
import com.ctrip.apollo.portal.entity.form.NamespaceReleaseModel;
import com.ctrip.apollo.portal.service.ConfigService;
import com.ctrip.apollo.portal.service.txtresolver.TextResolverResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
......@@ -34,7 +31,7 @@ public class ConfigController {
public List<NamespaceVO> findNamespaces(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName) {
if (StringUtils.isContainEmpty(appId, env, clusterName)) {
throw new IllegalArgumentException("app id and cluster name can not be empty");
throw new BadRequestException("app id and cluster name can not be empty");
}
return configService.findNampspaces(appId, Apollo.Env.valueOf(env), clusterName);
......@@ -42,9 +39,9 @@ public class ConfigController {
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = {
"application/json"})
public ResponseEntity<SimpleMsg> modifyItems(@PathVariable String appId, @PathVariable String env,
public ResponseEntity modifyItems(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@RequestBody NamespaceModifyModel model) {
@RequestBody NamespaceTextModel model) {
if (model == null) {
throw new BadRequestException("request payload shoud not be null");
......@@ -58,18 +55,13 @@ public class ConfigController {
throw new BadRequestException("request model is invalid");
}
TextResolverResult result = configService.resolveConfigText(model);
if (result.isResolveSuccess()) {
return ResponseEntity.ok().body(new SimpleMsg("success"));
} else {
return ResponseEntity.badRequest().body(new SimpleMsg(result.getMsg()));
}
configService.updateConfigItemByText(model);
return ResponseEntity.ok().build();
}
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/release", method = RequestMethod.POST, consumes = {
"application/json"})
public ResponseEntity<SimpleMsg> createRelease(@PathVariable String appId,
public ReleaseDTO createRelease(@PathVariable String appId,
@PathVariable String env, @PathVariable String clusterName,
@PathVariable String namespaceName, @RequestBody NamespaceReleaseModel model) {
if (model == null) {
......@@ -84,14 +76,8 @@ public class ConfigController {
throw new BadRequestException("request model is invalid");
}
ReleaseDTO release = configService.release(model);
return configService.createRelease(model);
if (release == null) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new SimpleMsg("oops! some error in server."));
} else {
return ResponseEntity.ok().body(new SimpleMsg("success"));
}
}
}
......@@ -4,7 +4,7 @@ package com.ctrip.apollo.portal.entity.form;
import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.core.utils.StringUtils;
public class NamespaceModifyModel implements FormModel{
public class NamespaceTextModel implements FormModel{
private String appId;
private String env;
......
......@@ -11,13 +11,13 @@ import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.dto.NamespaceDTO;
import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.exception.ServiceException;
import com.ctrip.apollo.core.utils.StringUtils;
import com.ctrip.apollo.portal.api.AdminServiceAPI;
import com.ctrip.apollo.portal.entity.form.NamespaceModifyModel;
import com.ctrip.apollo.portal.entity.form.NamespaceTextModel;
import com.ctrip.apollo.portal.entity.NamespaceVO;
import com.ctrip.apollo.portal.entity.form.NamespaceReleaseModel;
import com.ctrip.apollo.portal.service.txtresolver.ConfigTextResolver;
import com.ctrip.apollo.portal.service.txtresolver.TextResolverResult;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
......@@ -86,20 +86,20 @@ public class ConfigService {
String namespaceName = namespace.getNamespaceName();
//latest release
//latest createRelease
ReleaseDTO release = releaseAPI.loadLatestRelease(appId, env, clusterName, namespaceName);
Map<String, String> releaseItems = new HashMap<>();
if (release != null) {
try {
releaseItems = objectMapper.readValue(release.getConfigurations(), Map.class);
} catch (IOException e) {
logger.error("parse release json error. appId:{},env:{},clusterName:{},namespace:{}", appId,
logger.error("parse createRelease json error. appId:{},env:{},clusterName:{},namespace:{}", appId,
env, clusterName, namespaceName);
return namespaceVO;
}
}
//not release config items
//not createRelease config items
List<ItemDTO> items = itemAPI.findItems(appId, env, clusterName, namespaceName);
int modifiedItemCnt = 0;
for (ItemDTO itemDTO : items) {
......@@ -135,7 +135,7 @@ public class ConfigService {
* parse config text and update config items
* @return parse result
*/
public TextResolverResult resolveConfigText(NamespaceModifyModel model) {
public void updateConfigItemByText(NamespaceTextModel model) {
String appId = model.getAppId();
Apollo.Env env = model.getEnv();
String clusterName = model.getClusterName();
......@@ -143,36 +143,16 @@ public class ConfigService {
long namespaceId = model.getNamespaceId();
String configText = model.getConfigText();
TextResolverResult result = new TextResolverResult();
ItemChangeSets changeSets =
resolver.resolve(namespaceId, configText, itemAPI.findItems(appId, env, clusterName, namespaceName));
try {
result = resolver.resolve( namespaceId, configText, itemAPI.findItems(appId, env, clusterName, namespaceName));
changeSets.setModifyBy(model.getModifyBy());
enrichChangeSetBaseInfo(changeSets);
itemAPI.updateItems(appId, env, clusterName, namespaceName, changeSets);
} catch (Exception e) {
logger
.error("resolve config text error. app id:{}, env:{}, clusterName:{}, namespace:{}", appId, env, clusterName,
namespaceName, e);
result.setResolveSuccess(false);
result.setMsg("oops! server resolveConfigText config text error.");
return result;
}
if (result.isResolveSuccess()) {
try {
ItemChangeSets changeSets = result.getChangeSets();
changeSets.setModifyBy(model.getModifyBy());
enrichChangeSetBaseInfo(changeSets);
itemAPI.updateItems(appId, env, clusterName, namespaceName, changeSets);
} catch (Exception e) {
logger.error("resolve config text error. app id:{}, env:{}, clusterName:{}, namespace:{}", appId, env,
clusterName, namespaceName, e);
result.setResolveSuccess(false);
result.setMsg("oops! server update config error.");
return result;
}
} else {
logger.warn("resolve config text error by format error. app id:{}, env:{}, clusterName:{}, namespace:{},cause:{}",
appId,env, clusterName, namespaceName, result.getMsg());
throw new ServiceException("oops! call admin service config error. ");
}
return result;
}
private void enrichChangeSetBaseInfo(ItemChangeSets changeSets){
......@@ -182,10 +162,10 @@ public class ConfigService {
}
/**
* release config items
* createRelease config items
* @return
*/
public ReleaseDTO release(NamespaceReleaseModel model){
public ReleaseDTO createRelease(NamespaceReleaseModel model){
return releaseAPI.release(model.getAppId(), model.getEnv(), model.getClusterName(), model.getNamespaceName(),
model.getReleaseBy(), model.getReleaseComment());
}
......
package com.ctrip.apollo.portal.service.txtresolver;
import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO;
import java.util.List;
/**
* users can modify config in text mode.so need resolveConfigText text.
* users can modify config in text mode.so need updateConfigItemByText text.
*/
public interface ConfigTextResolver {
TextResolverResult resolve(long namespaceId, String configText, List<ItemDTO> baseItems);
ItemChangeSets resolve(long namespaceId, String configText, List<ItemDTO> baseItems);
}
......@@ -2,6 +2,7 @@ package com.ctrip.apollo.portal.service.txtresolver;
import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.exception.BadRequestException;
import com.ctrip.apollo.core.utils.StringUtils;
import com.ctrip.apollo.common.utils.BeanUtils;
......@@ -25,13 +26,10 @@ public class PropertyResolver implements ConfigTextResolver {
private static final String ITEM_SEPARATOR = "\n";
@Override
public TextResolverResult resolve(long namespaceId, String configText, List<ItemDTO> baseItems) {
public ItemChangeSets resolve(long namespaceId, String configText, List<ItemDTO> baseItems) {
TextResolverResult result = new TextResolverResult();
if (StringUtils.isEmpty(configText)){
result.setResolveSuccess(false);
result.setMsg("config text can not be empty");
return result;
throw new BadRequestException("config text can not be empty");
}
Map<Integer, ItemDTO> oldLineNumMapItem = BeanUtils.mapByKey("lineNum", baseItems);
......@@ -43,13 +41,10 @@ public class PropertyResolver implements ConfigTextResolver {
String[] newItems = configText.split(ITEM_SEPARATOR);
if (isHasRepeatKey(newItems)){
result.setResolveSuccess(false);
result.setMsg("config text has repeat key please check.");
return result;
throw new BadRequestException("config text has repeat key please check.");
}
ItemChangeSets changeSets = new ItemChangeSets();
result.setChangeSets(changeSets);
Map<Integer, String> newLineNumMapItem = new HashMap();//use for delete blank and comment item
int lineCounter = 1;
for (String newItem : newItems) {
......@@ -69,9 +64,7 @@ public class PropertyResolver implements ConfigTextResolver {
//normal item
} else {
if (!handleNormalLine(namespaceId, oldKeyMapItem, newItem, lineCounter, result)) {
return result;
}
handleNormalLine(namespaceId, oldKeyMapItem, newItem, lineCounter, changeSets);
}
lineCounter++;
......@@ -80,13 +73,12 @@ public class PropertyResolver implements ConfigTextResolver {
deleteCommentAndBlankItem(oldLineNumMapItem, newLineNumMapItem, changeSets);
deleteNormalKVItem(oldKeyMapItem, changeSets);
result.setResolveSuccess(true);
return result;
return changeSets;
}
private boolean isHasRepeatKey(String[] newItems){
Set<String> keys = new HashSet<>();
int lineCounter = 1;
int keyCount = 0;
for (String item: newItems){
if (!isCommentItem(item) && !isBlankItem(item)){
......@@ -94,8 +86,11 @@ public class PropertyResolver implements ConfigTextResolver {
String[] kv = parseKeyValueFromItem(item);
if (kv != null) {
keys.add(kv[0]);
}else {
throw new BadRequestException("line:" + lineCounter + " key value must separate by '='");
}
}
lineCounter ++;
}
return keyCount > keys.size();
......@@ -127,17 +122,13 @@ public class PropertyResolver implements ConfigTextResolver {
}
}
private boolean handleNormalLine(Long namespaceId, Map<String, ItemDTO> keyMapOldItem, String newItem,
int lineCounter, TextResolverResult result) {
ItemChangeSets changeSets = result.getChangeSets();
private void handleNormalLine(Long namespaceId, Map<String, ItemDTO> keyMapOldItem, String newItem,
int lineCounter, ItemChangeSets changeSets) {
String[] kv = parseKeyValueFromItem(newItem);
if (kv == null) {
result.setResolveSuccess(false);
result.setMsg(" line:" + lineCounter + " key value must separate by '='");
return false;
throw new BadRequestException("line:" + lineCounter + " key value must separate by '='");
}
String newKey = kv[0];
......@@ -153,7 +144,6 @@ public class PropertyResolver implements ConfigTextResolver {
lineCounter));
}
keyMapOldItem.remove(newKey);
return true;
}
private boolean isCommentItem(ItemDTO item) {
......
package com.ctrip.apollo.portal.service.txtresolver;
import com.ctrip.apollo.core.dto.ItemChangeSets;
public class TextResolverResult {
private boolean isResolveSuccess;
/**
* error msg
*/
private String msg = "";
private ItemChangeSets changeSets;
public boolean isResolveSuccess() {
return isResolveSuccess;
}
public void setResolveSuccess(boolean resolveSuccess) {
isResolveSuccess = resolveSuccess;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public ItemChangeSets getChangeSets() {
return changeSets;
}
public void setChangeSets(ItemChangeSets changeSets) {
this.changeSets = changeSets;
}
}
......@@ -141,7 +141,7 @@ application_module.controller("AppConfigController",
$scope.toggleTextEditStatus($scope.draft);
}, function (result) {
toastr.error(result.data.msg, "更新失败");
toastr.error(result.data.message, "更新失败");
}
);
......@@ -189,7 +189,7 @@ application_module.controller("AppConfigController",
refreshNamespaces();
}, function (result) {
toastr.error(result.data.msg, "发布失败");
toastr.error(result.data.message, "发布失败");
}
);
......
......@@ -250,7 +250,7 @@
</div>
</div>
<!--release modal-->
<!--createRelease modal-->
<div class="modal fade" id="releaseModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel3">
<div class="modal-dialog" role="document">
<div class="modal-content">
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册