All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pro.taskana.classification.rest.ClassificationDefinitionController Maven / Gradle / Ivy

package pro.taskana.classification.rest;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import pro.taskana.classification.api.ClassificationQuery;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.api.exceptions.ClassificationAlreadyExistException;
import pro.taskana.classification.api.exceptions.ClassificationNotFoundException;
import pro.taskana.classification.api.models.Classification;
import pro.taskana.classification.api.models.ClassificationSummary;
import pro.taskana.classification.rest.assembler.ClassificationRepresentationModelAssembler;
import pro.taskana.classification.rest.models.ClassificationRepresentationModel;
import pro.taskana.common.api.LoggerUtils;
import pro.taskana.common.api.exceptions.ConcurrencyException;
import pro.taskana.common.api.exceptions.DomainNotFoundException;
import pro.taskana.common.api.exceptions.InvalidArgumentException;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.common.rest.Mapping;

/** Controller for Importing / Exporting classifications. */
@SuppressWarnings("unused")
@RestController
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class ClassificationDefinitionController {

  private static final Logger LOGGER =
      LoggerFactory.getLogger(ClassificationDefinitionController.class);

  private final ClassificationService classificationService;

  private final ClassificationRepresentationModelAssembler
      classificationRepresentationModelAssembler;

  ClassificationDefinitionController(
      ClassificationService classificationService,
      ClassificationRepresentationModelAssembler classificationRepresentationModelAssembler) {
    this.classificationService = classificationService;
    this.classificationRepresentationModelAssembler = classificationRepresentationModelAssembler;
  }

  @GetMapping(path = Mapping.URL_CLASSIFICATIONDEFINITION)
  @Transactional(readOnly = true, rollbackFor = Exception.class)
  public ResponseEntity> exportClassifications(
      @RequestParam(required = false) String domain) throws ClassificationNotFoundException {
    LOGGER.debug("Entry to exportClassifications(domain= {})", domain);
    ClassificationQuery query = classificationService.createClassificationQuery();

    List summaries =
        domain != null ? query.domainIn(domain).list() : query.list();
    List export = new ArrayList<>();

    for (ClassificationSummary summary : summaries) {
      Classification classification =
          classificationService.getClassification(summary.getKey(), summary.getDomain());

      export.add(classificationRepresentationModelAssembler.toModel(classification));
    }

    ResponseEntity> response = ResponseEntity.ok(export);
    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Exit from exportClassifications(), returning {}", response);
    }

    return response;
  }

  @PostMapping(path = Mapping.URL_CLASSIFICATIONDEFINITION)
  @Transactional(rollbackFor = Exception.class)
  public ResponseEntity importClassifications(@RequestParam("file") MultipartFile file)
      throws InvalidArgumentException, NotAuthorizedException, ConcurrencyException,
          ClassificationNotFoundException, ClassificationAlreadyExistException,
          DomainNotFoundException, IOException {
    LOGGER.debug("Entry to importClassifications()");
    Map systemIds = getSystemIds();
    List classificationsResources =
        extractClassificationResourcesFromFile(file);
    checkForDuplicates(classificationsResources);

    Map childrenInFile =
        mapChildrenToParentKeys(classificationsResources, systemIds);
    insertOrUpdateClassificationsWithoutParent(classificationsResources, systemIds);
    updateParentChildrenRelations(childrenInFile);
    ResponseEntity response = ResponseEntity.noContent().build();
    LOGGER.debug("Exit from importClassifications(), returning {}", response);
    return response;
  }

  private Map getSystemIds() {
    return classificationService.createClassificationQuery().list().stream()
        .collect(
            Collectors.toMap(i -> i.getKey() + "|" + i.getDomain(), ClassificationSummary::getId));
  }

  private List extractClassificationResourcesFromFile(
      MultipartFile file) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    return mapper.readValue(
        file.getInputStream(), new TypeReference>() {});
  }

  private void checkForDuplicates(List classificationList) {
    List identifiers = new ArrayList<>();
    Set duplicates = new HashSet<>();
    for (ClassificationRepresentationModel classification : classificationList) {
      String identifier = classification.getKey() + "|" + classification.getDomain();
      if (identifiers.contains(identifier)) {
        duplicates.add(identifier);
      } else {
        identifiers.add(identifier);
      }
    }
    if (!duplicates.isEmpty()) {
      throw new DuplicateKeyException(
          "The 'key|domain'-identifier is not unique for the value(s): " + duplicates.toString());
    }
  }

  private Map mapChildrenToParentKeys(
      List classificationRepresentationModels,
      Map systemIds) {
    LOGGER.debug("Entry to mapChildrenToParentKeys()");
    Map childrenInFile = new HashMap<>();
    Set newKeysWithDomain = new HashSet<>();
    classificationRepresentationModels.forEach(
        cl -> newKeysWithDomain.add(cl.getKey() + "|" + cl.getDomain()));

    for (ClassificationRepresentationModel cl : classificationRepresentationModels) {
      cl.setParentId(cl.getParentId() == null ? "" : cl.getParentId());
      cl.setParentKey(cl.getParentKey() == null ? "" : cl.getParentKey());

      if (!cl.getParentId().equals("") && cl.getParentKey().equals("")) {
        for (ClassificationRepresentationModel parent : classificationRepresentationModels) {
          if (cl.getParentId().equals(parent.getClassificationId())) {
            cl.setParentKey(parent.getKey());
          }
        }
      }

      String parentKeyAndDomain = cl.getParentKey() + "|" + cl.getDomain();
      if ((!cl.getParentKey().isEmpty() && !cl.getParentKey().equals("") && (
          newKeysWithDomain.contains(parentKeyAndDomain)
              || systemIds.containsKey(parentKeyAndDomain)))) {
        childrenInFile.put(
            classificationRepresentationModelAssembler.toEntityModel(cl), cl.getParentKey());
      }
    }
    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug(
          "Exit from mapChildrenToParentKeys(), returning {}",
          LoggerUtils.mapToString(childrenInFile));
    }

    return childrenInFile;
  }

  private void insertOrUpdateClassificationsWithoutParent(
      List classificationRepresentationModels,
      Map systemIds)
      throws ClassificationNotFoundException, NotAuthorizedException, InvalidArgumentException,
          ClassificationAlreadyExistException, DomainNotFoundException, ConcurrencyException {
    LOGGER.debug("Entry to insertOrUpdateClassificationsWithoutParent()");

    for (ClassificationRepresentationModel classificationRepresentationModel :
        classificationRepresentationModels) {
      classificationRepresentationModel.setParentKey(null);
      classificationRepresentationModel.setParentId(null);
      classificationRepresentationModel.setClassificationId(null);

      String systemId =
          systemIds.get(
              classificationRepresentationModel.getKey()
                  + "|"
                  + classificationRepresentationModel.getDomain());
      if (systemId != null) {
        updateExistingClassification(classificationRepresentationModel, systemId);
      } else {
        classificationService.createClassification(
            classificationRepresentationModelAssembler
                .toEntityModel(classificationRepresentationModel));
      }
    }
    LOGGER.debug("Exit from insertOrUpdateClassificationsWithoutParent()");
  }

  private void updateParentChildrenRelations(Map childrenInFile)
      throws ClassificationNotFoundException, NotAuthorizedException, ConcurrencyException,
          InvalidArgumentException {
    LOGGER.debug("Entry to updateParentChildrenRelations()");

    for (Map.Entry entry : childrenInFile.entrySet()) {
      Classification childRes = entry.getKey();
      String parentKey = entry.getValue();
      String classificationKey = childRes.getKey();
      String classificationDomain = childRes.getDomain();

      Classification child =
          classificationService.getClassification(classificationKey, classificationDomain);
      String parentId =
          (parentKey == null)
              ? ""
              : classificationService.getClassification(parentKey, classificationDomain).getId();

      child.setParentKey(parentKey);
      child.setParentId(parentId);

      classificationService.updateClassification(child);
    }
    LOGGER.debug("Exit from updateParentChildrenRelations()");
  }

  private void updateExistingClassification(ClassificationRepresentationModel cl, String systemId)
      throws ClassificationNotFoundException, NotAuthorizedException, ConcurrencyException,
          InvalidArgumentException {
    LOGGER.debug("Entry to updateExistingClassification()");
    Classification currentClassification = classificationService.getClassification(systemId);
    if (cl.getType() != null && !cl.getType().equals(currentClassification.getType())) {
      throw new InvalidArgumentException("Can not change the type of a classification.");
    }
    currentClassification.setCategory(cl.getCategory());
    currentClassification.setIsValidInDomain(cl.getIsValidInDomain());
    currentClassification.setName(cl.getName());
    currentClassification.setParentId(cl.getParentId());
    currentClassification.setParentKey(cl.getParentKey());
    currentClassification.setDescription(cl.getDescription());
    currentClassification.setPriority(cl.getPriority());
    currentClassification.setServiceLevel(cl.getServiceLevel());
    currentClassification.setApplicationEntryPoint(cl.getApplicationEntryPoint());
    currentClassification.setCustom1(cl.getCustom1());
    currentClassification.setCustom2(cl.getCustom2());
    currentClassification.setCustom3(cl.getCustom3());
    currentClassification.setCustom4(cl.getCustom4());
    currentClassification.setCustom5(cl.getCustom5());
    currentClassification.setCustom6(cl.getCustom6());
    currentClassification.setCustom7(cl.getCustom7());
    currentClassification.setCustom8(cl.getCustom8());
    classificationService.updateClassification(currentClassification);
    LOGGER.debug("Exit from updateExistingClassification()");
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy