Coverage Report - com.ctrip.framework.apollo.portal.service.PortalConfigService
 
Classes in this File Line Coverage Branch Coverage Complexity
PortalConfigService
64%
74/115
64%
22/34
3.364
 
 1  
 package com.ctrip.framework.apollo.portal.service;
 2  
 
 3  
 
 4  
 import org.slf4j.Logger;
 5  
 import org.slf4j.LoggerFactory;
 6  
 import org.springframework.beans.factory.annotation.Autowired;
 7  
 import org.springframework.stereotype.Service;
 8  
 import org.springframework.util.CollectionUtils;
 9  
 import org.springframework.web.client.HttpClientErrorException;
 10  
 
 11  
 import com.ctrip.framework.apollo.common.utils.BeanUtils;
 12  
 import com.ctrip.framework.apollo.core.enums.Env;
 13  
 import com.ctrip.framework.apollo.core.dto.ItemChangeSets;
 14  
 import com.ctrip.framework.apollo.core.dto.ItemDTO;
 15  
 import com.ctrip.framework.apollo.core.dto.NamespaceDTO;
 16  
 import com.ctrip.framework.apollo.core.dto.ReleaseDTO;
 17  
 import com.ctrip.framework.apollo.core.exception.BadRequestException;
 18  
 import com.ctrip.framework.apollo.core.exception.NotFoundException;
 19  
 import com.ctrip.framework.apollo.core.exception.ServiceException;
 20  
 import com.ctrip.framework.apollo.core.utils.StringUtils;
 21  
 import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
 22  
 import com.ctrip.framework.apollo.portal.auth.UserInfoHolder;
 23  
 import com.ctrip.framework.apollo.portal.entity.vo.ItemDiffs;
 24  
 import com.ctrip.framework.apollo.portal.entity.vo.NamespaceIdentifer;
 25  
 import com.ctrip.framework.apollo.portal.entity.form.NamespaceTextModel;
 26  
 import com.ctrip.framework.apollo.portal.entity.form.NamespaceReleaseModel;
 27  
 import com.ctrip.framework.apollo.portal.service.txtresolver.ConfigTextResolver;
 28  
 
 29  
 import java.util.LinkedList;
 30  
 import java.util.List;
 31  
 import java.util.Map;
 32  
 
 33  
 @Service
 34  4
 public class PortalConfigService {
 35  
 
 36  4
   private Logger logger = LoggerFactory.getLogger(PortalConfigService.class);
 37  
 
 38  
   @Autowired
 39  
   private UserInfoHolder userInfoHolder;
 40  
   @Autowired
 41  
   private AdminServiceAPI.NamespaceAPI namespaceAPI;
 42  
   @Autowired
 43  
   private AdminServiceAPI.ItemAPI itemAPI;
 44  
   @Autowired
 45  
   private AdminServiceAPI.ReleaseAPI releaseAPI;
 46  
   @Autowired
 47  
   private ConfigTextResolver resolver;
 48  
 
 49  
 
 50  
   /**
 51  
    * parse config text and update config items
 52  
    *
 53  
    * @return parse result
 54  
    */
 55  
   public void updateConfigItemByText(NamespaceTextModel model) {
 56  1
     String appId = model.getAppId();
 57  1
     Env env = model.getEnv();
 58  1
     String clusterName = model.getClusterName();
 59  1
     String namespaceName = model.getNamespaceName();
 60  1
     long namespaceId = model.getNamespaceId();
 61  1
     String configText = model.getConfigText();
 62  
 
 63  2
     ItemChangeSets changeSets = resolver.resolve(namespaceId, configText,
 64  1
                                                  itemAPI.findItems(appId, env, clusterName, namespaceName));
 65  1
     if (changeSets.isEmpty()) {
 66  0
       return;
 67  
     }
 68  
 
 69  
     try {
 70  1
       changeSets.setDataChangeLastModifiedBy(userInfoHolder.getUser().getUserId());
 71  1
       itemAPI.updateItems(appId, env, clusterName, namespaceName, changeSets);
 72  0
     } catch (Exception e) {
 73  0
       logger.error("itemAPI.updateItems error. appId{},env:{},clusterName:{},namespaceName:{}", appId, env, clusterName,
 74  
                    namespaceName);
 75  0
       throw new ServiceException(e.getMessage());
 76  1
     }
 77  1
   }
 78  
 
 79  
 
 80  
   public ItemDTO createOrUpdateItem(String appId, Env env, String clusterName, String namespaceName, ItemDTO item) {
 81  0
     NamespaceDTO namespace = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName);
 82  0
     if (namespace == null) {
 83  0
       throw new BadRequestException(
 84  
           "namespace:" + namespaceName + " not exist in env:" + env + ", cluster:" + clusterName);
 85  
     }
 86  0
     String username = userInfoHolder.getUser().getUserId();
 87  0
     if (StringUtils.isEmpty(item.getDataChangeCreatedBy())) {
 88  0
       item.setDataChangeCreatedBy(username);
 89  
     }
 90  0
     item.setDataChangeLastModifiedBy(username);
 91  0
     item.setNamespaceId(namespace.getId());
 92  0
     return itemAPI.createOrUpdateItem(appId, env, clusterName, namespaceName, item);
 93  
   }
 94  
 
 95  
   public void deleteItem(Env env, long itemId) {
 96  0
     itemAPI.deleteItem(env, itemId, userInfoHolder.getUser().getUserId());
 97  0
   }
 98  
 
 99  
   /**
 100  
    * createRelease config items
 101  
    */
 102  
   public ReleaseDTO createRelease(NamespaceReleaseModel model) {
 103  0
     return releaseAPI.release(model.getAppId(), model.getEnv(), model.getClusterName(),
 104  0
                               model.getNamespaceName(), model.getReleaseBy(), model.getReleaseComment()
 105  0
         , userInfoHolder.getUser().getUserId());
 106  
   }
 107  
 
 108  
   public List<ItemDTO> findItems(String appId, Env env, String clusterName, String namespaceName) {
 109  0
     return itemAPI.findItems(appId, env, clusterName, namespaceName);
 110  
   }
 111  
 
 112  
   public void syncItems(List<NamespaceIdentifer> comparedNamespaces, List<ItemDTO> sourceItems) {
 113  0
     List<ItemDiffs> itemDiffs = compare(comparedNamespaces, sourceItems);
 114  0
     for (ItemDiffs itemDiff : itemDiffs) {
 115  0
       NamespaceIdentifer namespaceIdentifer = itemDiff.getNamespace();
 116  0
       ItemChangeSets changeSets = itemDiff.getDiffs();
 117  0
       changeSets.setDataChangeLastModifiedBy(userInfoHolder.getUser().getUserId());
 118  
       try {
 119  0
         itemAPI
 120  0
             .updateItems(namespaceIdentifer.getAppId(), namespaceIdentifer.getEnv(),
 121  0
                          namespaceIdentifer.getClusterName(),
 122  0
                          namespaceIdentifer.getNamespaceName(), changeSets);
 123  0
       } catch (HttpClientErrorException e) {
 124  0
         logger.error("sync items error. namespace:{}", namespaceIdentifer);
 125  0
         throw new ServiceException(String.format("sync item error. env:%s, clusterName:%s", namespaceIdentifer.getEnv(),
 126  0
                                                  namespaceIdentifer.getClusterName()), e);
 127  0
       }
 128  0
     }
 129  0
   }
 130  
 
 131  
   public List<ItemDiffs> compare(List<NamespaceIdentifer> comparedNamespaces, List<ItemDTO> sourceItems) {
 132  
 
 133  2
     List<ItemDiffs> result = new LinkedList<>();
 134  
 
 135  2
     for (NamespaceIdentifer namespace : comparedNamespaces) {
 136  
 
 137  2
       ItemDiffs itemDiffs = new ItemDiffs(namespace);
 138  2
       itemDiffs.setDiffs(parseChangeSets(namespace, sourceItems));
 139  2
       result.add(itemDiffs);
 140  2
     }
 141  
 
 142  2
     return result;
 143  
   }
 144  
 
 145  
   private long getNamespaceId(NamespaceIdentifer namespaceIdentifer) {
 146  2
     String appId = namespaceIdentifer.getAppId();
 147  2
     String clusterName = namespaceIdentifer.getClusterName();
 148  2
     String namespaceName = namespaceIdentifer.getNamespaceName();
 149  2
     Env env = namespaceIdentifer.getEnv();
 150  2
     NamespaceDTO namespaceDTO = null;
 151  
     try {
 152  2
       namespaceDTO = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName);
 153  0
     } catch (NotFoundException e) {
 154  0
       logger.warn("namespace not exist. appId:{}, env:{}, clusterName:{}, namespaceName:{}", appId, env, clusterName,
 155  
                   namespaceName);
 156  0
       throw new BadRequestException(String.format(
 157  
           "namespace not exist. appId:%s, env:%s, clusterName:%s, namespaceName:%s", appId, env, clusterName,
 158  
           namespaceName));
 159  2
     }
 160  2
     return namespaceDTO.getId();
 161  
   }
 162  
 
 163  
   private ItemChangeSets parseChangeSets(NamespaceIdentifer namespace, List<ItemDTO> sourceItems) {
 164  2
     ItemChangeSets changeSets = new ItemChangeSets();
 165  
     List<ItemDTO>
 166  2
         targetItems =
 167  4
         itemAPI.findItems(namespace.getAppId(), namespace.getEnv(),
 168  2
                           namespace.getClusterName(), namespace.getNamespaceName());
 169  
 
 170  2
     long namespaceId = getNamespaceId(namespace);
 171  
 
 172  2
     if (CollectionUtils.isEmpty(targetItems)) {//all source items is added
 173  1
       int lineNum = 1;
 174  1
       for (ItemDTO sourceItem : sourceItems) {
 175  1
         changeSets.addCreateItem(buildItem(namespaceId, lineNum++, sourceItem));
 176  1
       }
 177  1
     } else {
 178  1
       Map<String, ItemDTO> targetItemMap = BeanUtils.mapByKey("key", targetItems);
 179  
       String key, sourceValue, sourceComment;
 180  1
       ItemDTO targetItem = null;
 181  1
       int maxLineNum = targetItems.size();//append to last
 182  1
       for (ItemDTO sourceItem : sourceItems) {
 183  4
         key = sourceItem.getKey();
 184  4
         sourceValue = sourceItem.getValue();
 185  4
         sourceComment = sourceItem.getComment();
 186  4
         targetItem = targetItemMap.get(key);
 187  
 
 188  4
         if (targetItem == null) {//added items
 189  
 
 190  1
           changeSets.addCreateItem(buildItem(namespaceId, ++maxLineNum, sourceItem));
 191  
 
 192  6
         } else if (isModified(sourceValue, targetItem.getValue(), sourceComment,
 193  3
                               targetItem.getComment())) {//modified items
 194  2
           targetItem.setValue(sourceValue);
 195  2
           targetItem.setComment(sourceComment);
 196  2
           changeSets.addUpdateItem(targetItem);
 197  
         }
 198  4
       }
 199  
 
 200  
       //parse deleted items
 201  1
       List<ItemDTO> deletedItems = new LinkedList<>();
 202  1
       Map<String, ItemDTO> sourceItemMap = BeanUtils.mapByKey("key", sourceItems);
 203  1
       for (ItemDTO item : targetItems) {
 204  3
         if (sourceItemMap.get(item.getKey()) == null) {
 205  0
           deletedItems.add(item);
 206  
         }
 207  3
       }
 208  1
       changeSets.setDeleteItems(deletedItems);
 209  
     }
 210  
 
 211  2
     return changeSets;
 212  
   }
 213  
 
 214  
   private ItemDTO buildItem(long namespaceId, int lineNum, ItemDTO sourceItem) {
 215  2
     ItemDTO createdItem = new ItemDTO();
 216  2
     BeanUtils.copyEntityProperties(sourceItem, createdItem);
 217  2
     createdItem.setLineNum(lineNum++);
 218  2
     createdItem.setNamespaceId(namespaceId);
 219  2
     return createdItem;
 220  
   }
 221  
 
 222  
   private boolean isModified(String sourceValue, String targetValue, String sourceComment, String targetComment) {
 223  
 
 224  3
     if (!sourceValue.equals(targetValue)) {
 225  1
       return true;
 226  
     }
 227  
 
 228  2
     if (sourceComment == null) {
 229  0
       return !StringUtils.isEmpty(targetComment);
 230  2
     } else if (targetComment != null) {
 231  2
       return !sourceComment.equals(targetComment);
 232  
     } else {
 233  0
       return false;
 234  
     }
 235  
   }
 236  
 }