package kr.wisestone.owl.service.impl;
|
|
|
import com.google.common.collect.Lists;
|
import kr.wisestone.owl.constant.MsgConstants;
|
import kr.wisestone.owl.domain.IssueStatus;
|
import kr.wisestone.owl.domain.Workflow;
|
import kr.wisestone.owl.domain.WorkflowTransition;
|
import kr.wisestone.owl.domain.enumType.IssueStatusType;
|
import kr.wisestone.owl.domain.enumType.ProjectType;
|
import kr.wisestone.owl.exception.OwlRuntimeException;
|
import kr.wisestone.owl.repository.WorkflowTransitionRepository;
|
import kr.wisestone.owl.service.IssueStatusService;
|
import kr.wisestone.owl.service.WorkflowTransitionService;
|
import kr.wisestone.owl.util.MapUtil;
|
import kr.wisestone.owl.vo.IssueStatusVo;
|
import kr.wisestone.owl.vo.WorkflowTransitionVo;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
|
@Service
|
public class WorkflowTransitionServiceImpl extends AbstractServiceImpl<WorkflowTransition, Long, JpaRepository<WorkflowTransition, Long>> implements WorkflowTransitionService {
|
|
private static final Logger log = LoggerFactory.getLogger(WorkflowTransitionServiceImpl.class);
|
|
@Autowired
|
private WorkflowTransitionRepository workflowTransitionRepository;
|
|
@Autowired
|
private IssueStatusService issueStatusService;
|
|
@Override
|
protected JpaRepository<WorkflowTransition, Long> getRepository() {
|
return this.workflowTransitionRepository;
|
}
|
|
// 워크스페이스 생성시 기본 제공되는 이슈 상태를 연결하여 기본 제공되는 워크플로우을 생성한다.
|
@Override
|
@Transactional
|
public void addDefaultWorkflowTransition(Workflow workflow, List<IssueStatus> issueStatuses, ProjectType projectType) {
|
|
switch (projectType) {
|
case BTS_PROJECT:
|
// 생성 -> 진행 (1 -> 2)
|
// 진행 -> 확인 (2 -> 4)
|
// 확인 -> 재진행 (4 -> 3)
|
// 확인 -> 종료 (4 -> 5)
|
// 재진행 -> 진행 (3 -> 2)
|
// 재진행 -> 확인 (3 -> 4)
|
// 종료 -> 재진행 (5 -> 3)
|
this.makeWorkflowTransition(1L, 2L, issueStatuses, workflow, 47L, 186L, 173L, 186L, 77L, 183L);
|
this.makeWorkflowTransition(2L, 4L, issueStatuses, workflow, 173L, 186L, 313L, 185L, 139L, 186L);
|
this.makeWorkflowTransition(4L, 3L, issueStatuses, workflow, 313L, 185L, 312L, 34L, 219L, 89L);
|
this.makeWorkflowTransition(4L, 5L, issueStatuses, workflow, 313L, 185L, 493L, 185L, 380L, 186L);
|
this.makeWorkflowTransition(3L, 2L, issueStatuses, workflow, 312L, 34L, 173L, 186L, 78L, 43L);
|
this.makeWorkflowTransition(5L, 3L, issueStatuses, workflow, 493L, 185L, 312L, 34L, 490L, 40L);
|
|
break;
|
case RMS_PROJECT:
|
// 생성 -> 진행 (1 -> 2)
|
// 진행 -> 확인 (2 -> 4)
|
// 확인 -> 승인 불가 (4 -> 6)
|
// 확인 -> 승인 (4 -> 7)
|
// 승인 불가 -> 진행 (6 -> 2)
|
// 승인 불가 -> 종료 (6 -> 5)
|
// 승인 -> 종료 (7 -> 5)
|
// 종료 -> 진행 (5 -> 2)
|
this.makeWorkflowTransition(1L, 2L, issueStatuses, workflow, 73L, 45L, 297L, 42L, 73L, 45L);
|
this.makeWorkflowTransition(2L, 4L, issueStatuses, workflow, 297L, 42L, 297L, 141L, 244L, 95L);
|
this.makeWorkflowTransition(4L, 6L, issueStatuses, workflow, 297L, 141L, 79L, 153L, 292L, 132L);
|
this.makeWorkflowTransition(4L, 7L, issueStatuses, workflow, 297L, 141L, 515L, 150L, 292L, 132L);
|
this.makeWorkflowTransition(6L, 2L, issueStatuses, workflow, 79L, 153L, 297L, 42L, 79L, 153L);
|
this.makeWorkflowTransition(6L, 5L, issueStatuses, workflow, 79L, 153L, 298L, 223L, 79L, 153L);
|
this.makeWorkflowTransition(7L, 5L, issueStatuses, workflow, 515L, 150L, 298L, 223L, 515L, 150L);
|
this.makeWorkflowTransition(5L, 2L, issueStatuses, workflow, 298L, 223L, 297L, 42L, 388L, 118L);
|
break;
|
case TCM_PROJECT:
|
// 생성 -> 확인 (1 -> 4)
|
// 확인 -> 종료 (4 -> 5)
|
// 종료 -> 재진행 (5 -> 3)
|
// 재진행 -> 확인(3 -> 4)
|
this.makeWorkflowTransition(1L, 4L, issueStatuses, workflow, 121L, 133L, 298L, 132L, 179L, 132L);
|
this.makeWorkflowTransition(4L, 5L, issueStatuses, workflow, 298L, 133L, 466L, 133L, 272L, 131L);
|
this.makeWorkflowTransition(5L, 3L, issueStatuses, workflow, 466L, 133L, 298L, 38L, 466L, 133L);
|
this.makeWorkflowTransition(3L, 4L, issueStatuses, workflow, 298L, 38L, 298L, 132L, 219L, 68L);
|
break;
|
}
|
}
|
|
private void makeWorkflowTransition(Long startPosition, Long endPosition, List<IssueStatus> issueStatuses, Workflow workflow, Long sourceX, Long sourceY, Long targetX, Long targetY, Long correctX, Long correctY) {
|
IssueStatus start = null;
|
IssueStatus end = null;
|
|
for (IssueStatus issueStatus : issueStatuses) {
|
if (startPosition.equals(issueStatus.getPosition())) {
|
start = issueStatus;
|
}
|
|
if (endPosition.equals(issueStatus.getPosition())) {
|
end = issueStatus;
|
}
|
}
|
|
if (start == null) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.START_ISSUE_STATUS_NOT_EXIST));
|
}
|
|
if (end == null) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.END_ISSUE_STATUS_NOT_EXIST));
|
}
|
|
WorkflowTransition workflowTransition = new WorkflowTransition(workflow, start, end, sourceX, sourceY, targetX, targetY, correctX, correctY);
|
this.workflowTransitionRepository.saveAndFlush(workflowTransition);
|
}
|
|
|
// 워크플로우에서 사용되는 전체 전이선을 조회한다.
|
@Override
|
@Transactional(readOnly = true)
|
public List<WorkflowTransition> findByWorkflowId(Long workflowId) {
|
return this.workflowTransitionRepository.findByWorkflowId(workflowId);
|
}
|
|
// 워크플로우에 사용되는 이슈 상태인지 확인한다
|
@Override
|
public boolean contains(Long issueStatusId, Long workflowId) {
|
List<WorkflowTransitionVo> workflowTransitionVos = this.findBySourceIssueStatusIdAndWorkflowId(issueStatusId, workflowId);
|
return workflowTransitionVos != null && workflowTransitionVos.size() > 0;
|
}
|
|
// 이슈 상태와 연결된 전이선 정보를 조회한다.
|
@Override
|
@Transactional(readOnly = true)
|
public List<WorkflowTransitionVo> findBySourceIssueStatusIdAndWorkflowId(Long sourceStatusId, Long workflowId) {
|
return this.workflowTransitionRepository.findBySourceIssueStatusIdAndWorkflowId(sourceStatusId, workflowId);
|
}
|
|
// 전이선의 정보를 업데이트한다. 이미 존재하던 전이선이면 변경을 새로 생성된 전이선은 생성을 한다.
|
@Override
|
@Transactional
|
public void modify(Workflow workflow, List<IssueStatusVo> issueStatusVos) {
|
Map<String, Object> issueStatusMaps = new HashMap<>();
|
// 상태 속성 별로 1개씩 존재하는지 확인한다.
|
this.checkRequireIssueStatusType(issueStatusVos);
|
|
// 고립된 이슈 상태가 없는 워크플로우인지 확인한다.
|
this.checkIsolationWorkflow(issueStatusVos);
|
|
for (IssueStatusVo issueStatusVo : issueStatusVos) {
|
issueStatusMaps.put(issueStatusVo.getId().toString(), issueStatusVo);
|
}
|
|
// 해당 워크플로우의 전체 전이선 삭제
|
List<WorkflowTransition> removeWorkflowTransitions = this.workflowTransitionRepository.findByWorkflowId(workflow.getId());
|
|
if (removeWorkflowTransitions.size() > 0) {
|
this.removeWorkflowTransition(removeWorkflowTransitions);
|
}
|
|
for (IssueStatusVo issueStatusVo : issueStatusVos) {
|
for (WorkflowTransitionVo workflowTransitionVo : issueStatusVo.getWorkflowTransitionVos()) {
|
IssueStatus sourceIssueStatus = this.issueStatusService.getIssueStatus(workflowTransitionVo.getSourceStatusId());
|
IssueStatus targetIssueStatus = this.issueStatusService.getIssueStatus(workflowTransitionVo.getTargetStatusId());
|
IssueStatusVo sourceIssueStatusVo = (IssueStatusVo) MapUtil.getObject(issueStatusMaps, sourceIssueStatus.getId().toString());
|
IssueStatusVo targetIssueStatusVo = (IssueStatusVo) MapUtil.getObject(issueStatusMaps, targetIssueStatus.getId().toString());
|
|
|
WorkflowTransition workflowTransition = new WorkflowTransition(workflow, sourceIssueStatus, targetIssueStatus, sourceIssueStatusVo.getxLocation(), sourceIssueStatusVo.getyLocation(),
|
targetIssueStatusVo.getxLocation(), targetIssueStatusVo.getyLocation(), workflowTransitionVo.getCorrectX(), workflowTransitionVo.getCorrectY(), workflowTransitionVo.getDirect());
|
|
this.workflowTransitionRepository.save(workflowTransition);
|
}
|
}
|
}
|
|
// 상태 속성 별로 1개씩 존재하는지 확인한다.
|
private void checkRequireIssueStatusType(List<IssueStatusVo> issueStatusVos) {
|
boolean firstStatusExist = true;
|
boolean middleStatusExist = true;
|
boolean lastStatusExist = true;
|
|
for (IssueStatusVo issueStatusVo : issueStatusVos) {
|
switch (IssueStatusType.valueOf(issueStatusVo.getIssueStatusType())) {
|
case READY:
|
firstStatusExist = false;
|
break;
|
case OPEN:
|
middleStatusExist = false;
|
break;
|
case CLOSE:
|
lastStatusExist = false;
|
break;
|
}
|
}
|
|
if (firstStatusExist) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.WORKFLOW_REQUIRE_ISSUE_STATUS_TYPE_TO_READY));
|
}
|
|
if (middleStatusExist) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.WORKFLOW_REQUIRE_ISSUE_STATUS_TYPE_TO_OPEN));
|
}
|
|
if (lastStatusExist) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.WORKFLOW_REQUIRE_ISSUE_STATUS_TYPE_TO_CLOSE));
|
}
|
|
}
|
|
// 고립된 이슈 상태가 없는 워크플로우인지 확인한다.
|
private void checkIsolationWorkflow(List<IssueStatusVo> issueStatusVos) {
|
boolean firstCheck = false;
|
boolean middleCheck = false;
|
boolean lastCheck = true;
|
boolean connectCheck = false;
|
List<WorkflowTransitionVo> workflowTransitionVos = Lists.newArrayList();
|
|
// 전체 전이선 추출
|
for (IssueStatusVo issueStatusVo : issueStatusVos) {
|
for (WorkflowTransitionVo workflowTransitionVo : issueStatusVo.getWorkflowTransitionVos()) {
|
workflowTransitionVos.add(workflowTransitionVo);
|
}
|
}
|
|
// 시작 상태 정상 확인
|
for (IssueStatusVo issueStatusVo : issueStatusVos) {
|
switch (IssueStatusType.valueOf(issueStatusVo.getIssueStatusType())) {
|
case READY:
|
for (WorkflowTransitionVo workflowTransitionVo : workflowTransitionVos) {
|
if (workflowTransitionVo.getSourceStatusId().equals(issueStatusVo.getId())) {
|
firstCheck = true;
|
break;
|
}
|
|
}
|
break;
|
|
case OPEN:
|
boolean normalSourceCheck = false;
|
boolean normalTargetCheck = false;
|
middleCheck = true;
|
|
for (WorkflowTransitionVo workflowTransitionVo : workflowTransitionVos) {
|
if (workflowTransitionVo.getSourceStatusId().equals(issueStatusVo.getId())) {
|
normalSourceCheck = true;
|
}
|
|
if (workflowTransitionVo.getTargetStatusId().equals(issueStatusVo.getId())) {
|
normalTargetCheck = true;
|
}
|
}
|
|
if (!normalSourceCheck || !normalTargetCheck) {
|
connectCheck = true;
|
}
|
|
break;
|
|
case CLOSE:
|
boolean tempLastCheck = false;
|
|
for (WorkflowTransitionVo workflowTransitionVo : workflowTransitionVos) {
|
if (workflowTransitionVo.getTargetStatusId().equals(issueStatusVo.getId())) {
|
tempLastCheck = true;
|
break;
|
}
|
}
|
|
if (!tempLastCheck) {
|
lastCheck = false;
|
}
|
|
break;
|
}
|
}
|
|
if (!firstCheck || !middleCheck || !lastCheck || connectCheck) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.WORKFLOW_ISOLATION));
|
}
|
}
|
|
@Override
|
@Transactional(readOnly = true)
|
public WorkflowTransition getWorkflowTransition(Long id) {
|
if (id == null) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.WORKFLOW_TRANSITION_NOT_EXIST));
|
}
|
|
WorkflowTransition workflowTransition = this.findOne(id);
|
|
if (workflowTransition == null) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.WORKFLOW_TRANSITION_NOT_EXIST));
|
}
|
|
return workflowTransition;
|
}
|
|
private void removeWorkflowTransition(List<WorkflowTransition> workflowTransitions) {
|
for (WorkflowTransition workflowTransition : workflowTransitions) {
|
this.workflowTransitionRepository.delete(workflowTransition);
|
}
|
|
this.workflowTransitionRepository.flush();
|
}
|
|
|
}
|