ActivityFlowLinkManager.java
/*
* The coLAB project
* Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO
*
* Licensed under the MIT License
*/
package ch.colabproject.colab.api.controller.link;
import ch.colabproject.colab.api.controller.card.CardManager;
import ch.colabproject.colab.api.model.card.Card;
import ch.colabproject.colab.api.model.link.ActivityFlowLink;
import ch.colabproject.colab.api.persistence.jpa.link.ActivityFlowLinkDao;
import ch.colabproject.colab.generator.model.exceptions.HttpErrorMessage;
import ch.colabproject.colab.generator.model.exceptions.MessageI18nKey;
import java.util.Objects;
import java.util.Optional;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Activity flow link specific logic
*
* @author sandra
*/
@Stateless
@LocalBean
public class ActivityFlowLinkManager {
/** logger */
private static final Logger logger = LoggerFactory.getLogger(ActivityFlowLinkManager.class);
// *********************************************************************************************
// injections
// *********************************************************************************************
/**
* Activity flow link persistence handling
*/
@Inject
private ActivityFlowLinkDao linkDao;
/**
* Card specific logic handling
*/
@Inject
private CardManager cardManager;
// *********************************************************************************************
//
// *********************************************************************************************
/**
* Retrieve the activity flow link. If not found, throw a {@link HttpErrorMessage}.
*
* @param linkId the id of the activity flow link
*
* @return the activity flow link if found
*
* @throws HttpErrorMessage if the activity flow link was not found
*/
public ActivityFlowLink assertAndGetActivityFlowLink(Long linkId) {
ActivityFlowLink link = linkDao.findActivityFlowLink(linkId);
if (link == null) {
logger.error("activity flow link #{} not found", linkId);
throw HttpErrorMessage.dataError(MessageI18nKey.DATA_NOT_FOUND);
}
return link;
}
// *********************************************************************************************
//
// *********************************************************************************************
/**
* Create a link
*
* @param link the link to create
*
* @return the brand new link
*/
public ActivityFlowLink createActivityFlowLink(ActivityFlowLink link) {
logger.debug("create activity flow link {}", link);
// validation
if (!isValid(link.getPreviousCardId(), link.getNextCardId())) {
throw HttpErrorMessage.dataError(MessageI18nKey.DATA_INTEGRITY_FAILURE);
}
// fetch all objects and so ensure that they exist
Card previousCard = cardManager.assertAndGetCard(link.getPreviousCardId());
Card nextCard = cardManager.assertAndGetCard(link.getNextCardId());
if (!previousCard.getProject().equals(nextCard.getProject())) {
// prevent cross-project dependencies
throw HttpErrorMessage.badRequest();
}
ActivityFlowLink existingLink = getLink(previousCard, nextCard);
if (existingLink != null) {
// return pre-existing link silently
return existingLink;
} else {
// Such a link does not exist yet
// then make the modifications
link.setPreviousCard(previousCard);
link.setNextCard(nextCard);
ActivityFlowLink persistedLink = linkDao.persistActivityFlowLink(link);
previousCard.getActivityFlowLinksAsPrevious().add(persistedLink);
nextCard.getActivityFlowLinksAsNext().add(persistedLink);
return persistedLink;
}
}
/**
* Get any activity link from previous card to next card.
*
* @param previous link starting point
* @param next link end point
*
* @return the link if it exists or null
*/
private ActivityFlowLink getLink(Card previous, Card next) {
// make sur not to create same link twice
Optional<ActivityFlowLink> find = previous.getActivityFlowLinksAsPrevious().stream()
.filter(l -> l.getNextCard().equals(next))
.findFirst();
if (find.isEmpty()) {
return null;
} else {
return find.get();
}
}
/**
* Delete a link
*
* @param linkId the id of the link to delete
*/
public void deleteActivityFlowLink(Long linkId) {
logger.debug("delete activity flow link #{}", linkId);
// fetch all objects and so ensure that they exist
ActivityFlowLink link = assertAndGetActivityFlowLink(linkId);
Card previousCard = link.getPreviousCard();
if (previousCard == null) {
throw HttpErrorMessage.dataError(MessageI18nKey.DATA_INTEGRITY_FAILURE);
}
Card nextCard = link.getNextCard();
if (nextCard == null) {
throw HttpErrorMessage.dataError(MessageI18nKey.DATA_INTEGRITY_FAILURE);
}
// then make the modifications
previousCard.getActivityFlowLinksAsPrevious().remove(link);
nextCard.getActivityFlowLinksAsNext().remove(link);
linkDao.deleteActivityFlowLink(link);
}
/**
* Change the previous card
*
* @param linkId the id of the link to update
* @param newPreviousCardId the id of the new previous card
*/
public void changeActivityFlowLinkPrevious(Long linkId, Long newPreviousCardId) {
logger.debug("change previous card of activity flow link #{} with #{}", linkId,
newPreviousCardId);
// fetch all objects and so ensure that they exist
ActivityFlowLink link = assertAndGetActivityFlowLink(linkId);
// validation
if (!isValid(newPreviousCardId, link.getNextCardId())) {
throw HttpErrorMessage.dataError(MessageI18nKey.DATA_INTEGRITY_FAILURE);
}
Card oldPreviousCard = cardManager.assertAndGetCard(link.getPreviousCardId());
Card newPreviousCard = cardManager.assertAndGetCard(newPreviousCardId);
ActivityFlowLink existingLink = getLink(newPreviousCard, link.getNextCard());
if (existingLink != null) {
// such a link already exists
// preserve pre-existing and delete this one
deleteActivityFlowLink(link.getId());
} else {
// then make the modifications
oldPreviousCard.getActivityFlowLinksAsPrevious().remove(link);
link.setPreviousCard(newPreviousCard);
newPreviousCard.getActivityFlowLinksAsPrevious().add(link);
}
}
/**
* Change the next card
*
* @param linkId the id of the link to update
* @param newNextCardId the id of the new next card
*/
public void changeActivityFlowLinkNext(Long linkId, Long newNextCardId) {
logger.debug("change next card of activity flow link #{} with #{}", linkId,
newNextCardId);
// fetch all objects and so ensure that they exist
ActivityFlowLink link = assertAndGetActivityFlowLink(linkId);
// validation
if (!isValid(link.getPreviousCardId(), newNextCardId)) {
throw HttpErrorMessage.dataError(MessageI18nKey.DATA_INTEGRITY_FAILURE);
}
Card oldNext = cardManager.assertAndGetCard(link.getNextCardId());
Card newNext = cardManager.assertAndGetCard(newNextCardId);
ActivityFlowLink existingLink = getLink(link.getPreviousCard(), newNext);
if (existingLink != null) {
// such a link already exists
// preserve pre-existing and delete this one
deleteActivityFlowLink(link.getId());
} else {
// then make the modifications
oldNext.getActivityFlowLinksAsNext().remove(link);
link.setNextCard(newNext);
newNext.getActivityFlowLinksAsNext().add(link);
}
}
/**
* Check if the link is valid
*
* @param previousCardId the id of the previous card
* @param nextCardId the id of the next card
*
* @return
*/
private boolean isValid(Long previousCardId, Long nextCardId) {
return !Objects.equals(previousCardId, nextCardId);
}
// *********************************************************************************************
//
// *********************************************************************************************
}