content: package com.ctrip.framework.apollo.biz.service;
  
  
  import com.ctrip.framework.apollo.biz.config.BizConfig;
  import com.ctrip.framework.apollo.biz.entity.Audit;
  import com.ctrip.framework.apollo.biz.entity.Item;
  import com.ctrip.framework.apollo.biz.entity.Namespace;
  import com.ctrip.framework.apollo.biz.repository.ItemRepository;
  import com.ctrip.framework.apollo.common.exception.BadRequestException;
  import com.ctrip.framework.apollo.common.exception.NotFoundException;
  import com.ctrip.framework.apollo.common.utils.BeanUtils;
  import com.ctrip.framework.apollo.core.utils.StringUtils;
  
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  
  import java.util.Collections;
  import java.util.Date;
  import java.util.List;
  import java.util.Map;
  
  @Service
  public class ItemService {
  
    @Autowired
    private ItemRepository itemRepository;
  
    @Autowired
    private NamespaceService namespaceService;
  
    @Autowired
    private AuditService auditService;
  
    @Autowired
    private BizConfig bizConfig;
  
  
    @Transactional
    public Item delete(long id, String operator) {
      Item item = itemRepository.findOne(id);
      if (item == null) {
        throw new IllegalArgumentException("item not exist. ID:" + id);
      }
  
      item.setDeleted(true);
      item.setDataChangeLastModifiedBy(operator);
      Item deletedItem = itemRepository.save(item);
  
      auditService.audit(Item.class.getSimpleName(), id, Audit.OP.DELETE, operator);
      return deletedItem;
    }
  
    @Transactional
    public int batchDelete(long namespaceId, String operator) {
      return itemRepository.deleteByNamespaceId(namespaceId, operator);
  
    }
  
    public Item findOne(String appId, String clusterName, String namespaceName, String key) {
      Namespace namespace = namespaceService.findOne(appId, clusterName, namespaceName);
      if (namespace == null) {
        throw new NotFoundException(
            String.format("namespace not found for %s %s %s", appId, clusterName, namespaceName));
      }
      Item item = itemRepository.findByNamespaceIdAndKey(namespace.getId(), key);
      return item;
    }
  
    public Item findLastOne(String appId, String clusterName, String namespaceName) {
      Namespace namespace = namespaceService.findOne(appId, clusterName, namespaceName);
      if (namespace == null) {
        throw new NotFoundException(
            String.format("namespace not found for %s %s %s", appId, clusterName, namespaceName));
      }
      return findLastOne(namespace.getId());
    }
  
    public Item findLastOne(long namespaceId) {
      return itemRepository.findFirst1ByNamespaceIdOrderByLineNumDesc(namespaceId);
    }
  
    public Item findOne(long itemId) {
      Item item = itemRepository.findOne(itemId);
      return item;
    }
  
    public List<Item> findItemsWithoutOrdered(Long namespaceId) {
      List<Item> items = itemRepository.findByNamespaceId(namespaceId);
      if (items == null) {
        return Collections.emptyList();
      }
      return items;
    }
  
    public List<Item> findItemsWithoutOrdered(String appId, String clusterName, String namespaceName) {
      Namespace namespace = namespaceService.findOne(appId, clusterName, namespaceName);
      if (namespace != null) {
        return findItemsWithoutOrdered(namespace.getId());
      } else {
        return Collections.emptyList();
      }
    }
  
    public List<Item> findItemsWithOrdered(Long namespaceId) {
      List<Item> items = itemRepository.findByNamespaceIdOrderByLineNumAsc(namespaceId);
      if (items == null) {
        return Collections.emptyList();
      }
      return items;
    }
  
    public List<Item> findItemsWithOrdered(String appId, String clusterName, String namespaceName) {
      Namespace namespace = namespaceService.findOne(appId, clusterName, namespaceName);
      if (namespace != null) {
        return findItemsWithOrdered(namespace.getId());
      } else {
        return Collections.emptyList();
      }
    }
  
    public List<Item> findItemsModifiedAfterDate(long namespaceId, Date date) {
      return itemRepository.findByNamespaceIdAndDataChangeLastModifiedTimeGreaterThan(namespaceId, date);
    }
  
    @Transactional
    public Item save(Item entity) {
      checkItemKeyLength(entity.getKey());
      checkItemValueLength(entity.getNamespaceId(), entity.getValue());
  
      entity.setId(0);//protection
  
      if (entity.getLineNum() == 0) {
        Item lastItem = findLastOne(entity.getNamespaceId());
        int lineNum = lastItem == null ? 1 : lastItem.getLineNum() + 1;
        entity.setLineNum(lineNum);
      }
  
      Item item = itemRepository.save(entity);
  
      auditService.audit(Item.class.getSimpleName(), item.getId(), Audit.OP.INSERT,
                         item.getDataChangeCreatedBy());
  
      return item;
    }
  
    @Transactional
    public Item update(Item item) {
      checkItemValueLength(item.getNamespaceId(), item.getValue());
      Item managedItem = itemRepository.findOne(item.getId());
      BeanUtils.copyEntityProperties(item, managedItem);
      managedItem = itemRepository.save(managedItem);
  
      auditService.audit(Item.class.getSimpleName(), managedItem.getId(), Audit.OP.UPDATE,
                         managedItem.getDataChangeLastModifiedBy());
  
      return managedItem;
    }
  
    private boolean checkItemValueLength(long namespaceId, String value) {
      int limit = getItemValueLengthLimit(namespaceId);
      if (!StringUtils.isEmpty(value) && value.length() > limit) {
        throw new BadRequestException("value too long. length limit:" + limit);
      }
      return true;
    }
  
    private boolean checkItemKeyLength(String key) {
      if (!StringUtils.isEmpty(key) && key.length() > bizConfig.itemKeyLengthLimit()) {
        throw new BadRequestException("key too long. length limit:" + bizConfig.itemKeyLengthLimit());
      }
      return true;
    }
  
    private int getItemValueLengthLimit(long namespaceId) {
      Map<Long, Integer> namespaceValueLengthOverride = bizConfig.namespaceValueLengthLimitOverride();
      if (namespaceValueLengthOverride != null && namespaceValueLengthOverride.containsKey(namespaceId)) {
        return namespaceValueLengthOverride.get(namespaceId);
      }
      return bizConfig.itemValueLengthLimit();
    }
  
  }
  