Commit ca10ff38 authored by Szymon Wolarz's avatar Szymon Wolarz

SSHOC-24 items update versioning

Refactor all item subclasses
parent 68b3628c
package eu.sshopencloud.marketplace.model.workflows;
import eu.sshopencloud.marketplace.model.items.Item;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.*;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Entity
......@@ -15,14 +13,13 @@ import java.util.List;
@Data
@ToString(callSuper = true, exclude = {"workflow", "step"})
@EqualsAndHashCode(callSuper = true, exclude = {"workflow", "step"})
@NoArgsConstructor
public class Step extends Item {
public class Step extends Item implements StepParent {
@ManyToOne(optional = true, fetch = FetchType.EAGER, cascade = { CascadeType.REFRESH })
@ManyToOne(optional = true, fetch = FetchType.EAGER, cascade = { CascadeType.REFRESH, CascadeType.MERGE })
@JoinColumn(foreignKey = @ForeignKey(name="step_workflow_id_fk"))
private Workflow workflow;
@ManyToOne(optional = true, fetch = FetchType.EAGER, cascade = { CascadeType.REFRESH })
@ManyToOne(optional = true, fetch = FetchType.EAGER, cascade = { CascadeType.REFRESH, CascadeType.MERGE })
@JoinColumn(foreignKey = @ForeignKey(name="step_step_id_fk"))
private Step step;
......@@ -30,4 +27,49 @@ public class Step extends Item {
@OrderColumn(name = "ord")
private List<Step> substeps;
public Step() {
super();
this.substeps = new ArrayList<>();
}
private boolean isSubStep() {
return (workflow == null);
}
public StepParent getStepParent() {
if (isSubStep())
return step;
return workflow;
}
public Workflow getRootWorkflow() {
return getStepParent().getRootWorkflow();
}
@Override
public List<Step> getSteps() {
return Collections.unmodifiableList(substeps);
}
@Override
public void appendStep(@NonNull Step step) {
beforeStepAdd(step);
substeps.add(step);
}
@Override
public void addStep(@NonNull Step step, int stepNo) {
if (stepNo <= 0 || stepNo > substeps.size())
throw new IllegalArgumentException(String.format("Invalid step number: %d", stepNo));
beforeStepAdd(step);
substeps.add(stepNo - 1, step);
}
private void beforeStepAdd(Step step) {
substeps.removeIf(s -> s.getId().equals(step.getId()));
step.setStep(this);
}
}
package eu.sshopencloud.marketplace.model.workflows;
import java.util.List;
public interface StepParent {
List<Step> getSteps();
void appendStep(Step step);
void addStep(Step step, int stepNo);
Workflow getRootWorkflow();
}
......@@ -3,21 +3,56 @@ package eu.sshopencloud.marketplace.model.workflows;
import eu.sshopencloud.marketplace.model.items.Item;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Entity
@Table(name = "workflows")
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class Workflow extends Item {
public class Workflow extends Item implements StepParent {
@OneToMany(mappedBy = "workflow", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
@OrderColumn(name = "ord")
private List<Step> steps;
public Workflow() {
super();
this.steps = new ArrayList<>();
}
@Override
public void appendStep(@NonNull Step step) {
beforeStepAdd(step);
steps.add(step);
}
@Override
public void addStep(@NonNull Step step, int stepNo) {
if (stepNo <= 0 || stepNo > steps.size())
throw new IllegalArgumentException(String.format("Invalid step number: %d", stepNo));
beforeStepAdd(step);
steps.add(stepNo - 1, step);
}
private void beforeStepAdd(Step step) {
steps.removeIf(s -> s.getId().equals(step.getId()));
step.setWorkflow(this);
}
@Override
public List<Step> getSteps() {
return Collections.unmodifiableList(steps);
}
@Override
public Workflow getRootWorkflow() {
return this;
}
}
......@@ -6,13 +6,10 @@ import eu.sshopencloud.marketplace.dto.datasets.DatasetDto;
import eu.sshopencloud.marketplace.dto.datasets.PaginatedDatasets;
import eu.sshopencloud.marketplace.mappers.datasets.DatasetMapper;
import eu.sshopencloud.marketplace.model.datasets.Dataset;
import eu.sshopencloud.marketplace.model.items.Item;
import eu.sshopencloud.marketplace.repositories.datasets.DatasetRepository;
import eu.sshopencloud.marketplace.services.auth.LoggedInUserHolder;
import eu.sshopencloud.marketplace.services.items.ItemRelatedItemService;
import eu.sshopencloud.marketplace.services.items.ItemService;
import eu.sshopencloud.marketplace.services.search.IndexService;
import eu.sshopencloud.marketplace.validators.datasets.DatasetValidator;
import eu.sshopencloud.marketplace.validators.datasets.DatasetFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
......@@ -32,13 +29,8 @@ import java.util.stream.Collectors;
public class DatasetService {
private final DatasetRepository datasetRepository;
private final DatasetValidator datasetValidator;
private final DatasetFactory datasetFactory;
private final ItemService itemService;
private final ItemRelatedItemService itemRelatedItemService;
private final IndexService indexService;
......@@ -65,46 +57,32 @@ public class DatasetService {
}
public DatasetDto createDataset(DatasetCore datasetCore) {
Dataset dataset = datasetValidator.validate(datasetCore, null);
itemService.updateInfoDates(dataset);
itemService.addInformationContributorToItem(dataset, LoggedInUserHolder.getLoggedInUser());
Item nextVersion = itemService.clearVersionForCreate(dataset);
dataset = datasetRepository.save(dataset);
itemService.switchVersion(dataset, nextVersion);
indexService.indexItem(dataset);
return itemService.completeItem(DatasetMapper.INSTANCE.toDto(dataset));
return createNewDatasetVersion(datasetCore, null);
}
public DatasetDto updateDataset(Long id, DatasetCore datasetCore) {
if (!datasetRepository.existsById(id)) {
if (!datasetRepository.existsById(id))
throw new EntityNotFoundException("Unable to find " + Dataset.class.getName() + " with id " + id);
}
Dataset dataset = datasetValidator.validate(datasetCore, id);
itemService.updateInfoDates(dataset);
itemService.addInformationContributorToItem(dataset, LoggedInUserHolder.getLoggedInUser());
return createNewDatasetVersion(datasetCore, id);
}
private DatasetDto createNewDatasetVersion(DatasetCore datasetCore, Long prevDatasetId) {
Dataset prevDataset = (prevDatasetId != null) ? datasetRepository.getOne(prevDatasetId) : null;
Dataset dataset = datasetFactory.create(datasetCore, prevDataset);
Item prevVersion = dataset.getPrevVersion();
Item nextVersion = itemService.clearVersionForUpdate(dataset);
dataset = datasetRepository.save(dataset);
itemService.switchVersion(prevVersion, nextVersion);
indexService.indexItem(dataset);
return itemService.completeItem(DatasetMapper.INSTANCE.toDto(dataset));
}
public void deleteDataset(Long id) {
if (!datasetRepository.existsById(id)) {
throw new EntityNotFoundException("Unable to find " + Dataset.class.getName() + " with id " + id);
}
Dataset dataset = datasetRepository.getOne(id);
itemRelatedItemService.deleteRelationsForItem(dataset);
Item prevVersion = dataset.getPrevVersion();
Item nextVersion = itemService.clearVersionForDelete(dataset);
Dataset dataset = datasetRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("Unable to find " + Dataset.class.getName() + " with id " + id));
itemService.cleanupItem(dataset);
datasetRepository.delete(dataset);
itemService.switchVersion(prevVersion, nextVersion);
indexService.removeItem(dataset);
}
}
......@@ -28,37 +28,15 @@ import java.util.stream.Collectors;
public class ItemService {
private final ItemRepository itemRepository;
private final ItemRelatedItemService itemRelatedItemService;
private final PropertyTypeService propertyTypeService;
private final UserRepository userRepository;
private final SourceRepository sourceRepository;
public List<ItemBasicDto> getItems(Long sourceId, String sourceItemId) {
List<Item> items = itemRepository.findBySourceIdAndSourceItemId(sourceId, sourceItemId);
return items.stream().map(ItemConverter::convertItem).collect(Collectors.toList());
}
public void addInformationContributorToItem(Item item, User contributor) {
User user = userRepository.findByUsername(contributor.getUsername());
item.addInformationContributor(contributor);
}
public void updateInfoDates(Item item) {
ZonedDateTime now = ZonedDateTime.now();
item.setLastInfoUpdate(now);
if (item.getSource() != null) {
item.getSource().setLastHarvestedDate(now);
sourceRepository.save(item.getSource());
}
}
public List<ItemBasicDto> getNewerVersionsOfItem(Long itemId) {
// TODO change to recursive subordinates query in ItemRepository
List<ItemBasicDto> versions = new ArrayList<>();
......
......@@ -7,8 +7,6 @@ import eu.sshopencloud.marketplace.dto.tools.ToolDto;
import eu.sshopencloud.marketplace.mappers.tools.ToolMapper;
import eu.sshopencloud.marketplace.model.tools.Tool;
import eu.sshopencloud.marketplace.repositories.tools.ToolRepository;
import eu.sshopencloud.marketplace.services.auth.LoggedInUserHolder;
import eu.sshopencloud.marketplace.services.items.ItemRelatedItemService;
import eu.sshopencloud.marketplace.services.items.ItemService;
import eu.sshopencloud.marketplace.services.search.IndexService;
import eu.sshopencloud.marketplace.validators.tools.ToolFactory;
......@@ -32,7 +30,6 @@ public class ToolService {
private final ToolRepository toolRepository;
private final ToolFactory toolFactory;
private final ItemService itemService;
private final ItemRelatedItemService itemRelatedItemService;
private final IndexService indexService;
......@@ -59,20 +56,19 @@ public class ToolService {
}
public ToolDto createTool(ToolCore toolCore) {
return createNewTool(toolCore, null);
return createNewToolVersion(toolCore, null);
}
public ToolDto updateTool(Long id, ToolCore toolCore) {
if (!toolRepository.existsById(id))
throw new EntityNotFoundException("Unable to find " + Tool.class.getName() + " with id " + id);
return createNewTool(toolCore, id);
return createNewToolVersion(toolCore, id);
}
private ToolDto createNewTool(ToolCore toolCore, Long prevToolId) {
Tool tool = toolFactory.create(toolCore, prevToolId);
itemService.updateInfoDates(tool);
itemService.addInformationContributorToItem(tool, LoggedInUserHolder.getLoggedInUser());
private ToolDto createNewToolVersion(ToolCore toolCore, Long prevToolId) {
Tool prevTool = (prevToolId != null) ? toolRepository.getOne(prevToolId) : null;
Tool tool = toolFactory.create(toolCore, prevTool);
tool = toolRepository.save(tool);
indexService.indexItem(tool);
......@@ -90,5 +86,4 @@ public class ToolService {
toolRepository.delete(tool);
indexService.removeItem(tool);
}
}
......@@ -7,8 +7,6 @@ import eu.sshopencloud.marketplace.dto.trainings.TrainingMaterialDto;
import eu.sshopencloud.marketplace.mappers.trainings.TrainingMaterialMapper;
import eu.sshopencloud.marketplace.model.trainings.TrainingMaterial;
import eu.sshopencloud.marketplace.repositories.trainings.TrainingMaterialRepository;
import eu.sshopencloud.marketplace.services.auth.LoggedInUserHolder;
import eu.sshopencloud.marketplace.services.items.ItemRelatedItemService;
import eu.sshopencloud.marketplace.services.items.ItemService;
import eu.sshopencloud.marketplace.services.search.IndexService;
import eu.sshopencloud.marketplace.validators.ValidationException;
......@@ -34,7 +32,6 @@ public class TrainingMaterialService {
private final TrainingMaterialRepository trainingMaterialRepository;
private final TrainingMaterialFactory trainingMaterialFactory;
private final ItemService itemService;
private final ItemRelatedItemService itemRelatedItemService;
private final IndexService indexService;
......@@ -61,7 +58,7 @@ public class TrainingMaterialService {
}
public TrainingMaterialDto createTrainingMaterial(TrainingMaterialCore trainingMaterialCore) throws ValidationException {
return createNewTrainingMaterial(trainingMaterialCore, null);
return createNewTrainingMaterialVersion(trainingMaterialCore, null);
}
public TrainingMaterialDto updateTrainingMaterial(Long id, TrainingMaterialCore trainingMaterialCore)
......@@ -70,15 +67,16 @@ public class TrainingMaterialService {
if (!trainingMaterialRepository.existsById(id))
throw new EntityNotFoundException("Unable to find " + TrainingMaterial.class.getName() + " with id " + id);
return createNewTrainingMaterial(trainingMaterialCore, id);
return createNewTrainingMaterialVersion(trainingMaterialCore, id);
}
private TrainingMaterialDto createNewTrainingMaterial(TrainingMaterialCore trainingMaterialCore,
Long prevTrainingMaterialId) throws ValidationException {
private TrainingMaterialDto createNewTrainingMaterialVersion(TrainingMaterialCore trainingMaterialCore,
Long prevTrainingMaterialId) throws ValidationException {
TrainingMaterial trainingMaterial = trainingMaterialFactory.create(trainingMaterialCore, prevTrainingMaterialId);
itemService.updateInfoDates(trainingMaterial);
itemService.addInformationContributorToItem(trainingMaterial, LoggedInUserHolder.getLoggedInUser());
TrainingMaterial prevTrainingMaterial =
(prevTrainingMaterialId != null) ? trainingMaterialRepository.getOne(prevTrainingMaterialId) : null;
TrainingMaterial trainingMaterial = trainingMaterialFactory.create(trainingMaterialCore, prevTrainingMaterial);
trainingMaterial = trainingMaterialRepository.save(trainingMaterial);
indexService.indexItem(trainingMaterial);
......
......@@ -3,23 +3,20 @@ package eu.sshopencloud.marketplace.services.workflows;
import eu.sshopencloud.marketplace.dto.workflows.StepCore;
import eu.sshopencloud.marketplace.dto.workflows.StepDto;
import eu.sshopencloud.marketplace.mappers.workflows.StepMapper;
import eu.sshopencloud.marketplace.model.items.Item;
import eu.sshopencloud.marketplace.model.workflows.Step;
import eu.sshopencloud.marketplace.model.workflows.StepParent;
import eu.sshopencloud.marketplace.model.workflows.Workflow;
import eu.sshopencloud.marketplace.repositories.workflows.StepRepository;
import eu.sshopencloud.marketplace.repositories.workflows.WorkflowRepository;
import eu.sshopencloud.marketplace.services.auth.LoggedInUserHolder;
import eu.sshopencloud.marketplace.services.items.ItemRelatedItemService;
import eu.sshopencloud.marketplace.services.items.ItemService;
import eu.sshopencloud.marketplace.validators.workflows.StepValidator;
import eu.sshopencloud.marketplace.validators.workflows.StepFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityNotFoundException;
import java.util.ArrayList;
import java.util.List;
@Service
@Transactional
......@@ -28,18 +25,14 @@ import java.util.List;
public class StepService {
private final StepRepository stepRepository;
private final WorkflowRepository workflowRepository;
private final StepValidator stepValidator;
private final ItemRelatedItemService itemRelatedItemService;
private final StepFactory stepFactory;
private final ItemService itemService;
public StepDto getStep(long workflowId, long stepId) {
Step step = checkWorkflowAndStepConsistency(workflowId, stepId);
validateWorkflowAndStepConsistency(workflowId, stepId);
Step step = stepRepository.getOne(stepId);
return completeStep(StepMapper.INSTANCE.toDto(step));
}
......@@ -49,135 +42,67 @@ public class StepService {
}
public StepDto createStep(long workflowId, StepCore stepCore) {
Workflow workflow = workflowRepository.findById(workflowId)
.orElseThrow(() -> new EntityNotFoundException("Unable to find " + Workflow.class.getName() + " with id " + workflowId));
int numberOfSiblings = 0;
List<Step> steps = new ArrayList<>();
if (workflow.getSteps() != null) {
numberOfSiblings = workflow.getSteps().size();
steps = workflow.getSteps();
} else {
workflow.setSteps(steps);
}
Step step = stepValidator.validate(stepCore, null, numberOfSiblings);
step.setWorkflow(workflow);
itemService.updateInfoDates(step);
itemService.addInformationContributorToItem(step, LoggedInUserHolder.getLoggedInUser());
Workflow workflow = workflowRepository.findById(workflowId).orElseThrow(
() -> new EntityNotFoundException("Unable to find " + Workflow.class.getName() + " with id " + workflowId)
);
Item nextVersion = itemService.clearVersionForCreate(step);
step = stepRepository.save(step);
if (stepCore.getStepNo() == null) {
steps.add(step);
} else {
steps.add(stepCore.getStepNo() - 1, step);
}
workflowRepository.save(workflow);
itemService.switchVersion(step, nextVersion);
return completeStep(StepMapper.INSTANCE.toDto(step));
return createNewStep(workflow, stepCore);
}
public StepDto createStep(long workflowId, long stepId, StepCore substepCore) {
Step step = checkWorkflowAndStepConsistency(workflowId, stepId);
int numberOfSiblings = 0;
List<Step> substeps = new ArrayList<>();
if (step.getSubsteps() != null) {
numberOfSiblings = step.getSubsteps().size();
substeps = step.getSubsteps();
} else {
step.setSubsteps(substeps);
}
Step substep = stepValidator.validate(substepCore, null, numberOfSiblings);
substep.setStep(step);
itemService.updateInfoDates(substep);
validateWorkflowAndStepConsistency(workflowId, stepId);
StepParent parentStep = stepRepository.getOne(stepId);
itemService.addInformationContributorToItem(substep, LoggedInUserHolder.getLoggedInUser());
Item nextVersion = itemService.clearVersionForCreate(substep);
substep = stepRepository.save(substep);
return createNewStep(parentStep, substepCore);
}
if (substepCore.getStepNo() == null) {
substeps.add(substep);
} else {
substeps.add(substepCore.getStepNo() - 1, substep);
}
stepRepository.save(step);
private StepDto createNewStep(StepParent stepParent, StepCore stepCore) {
Step step = stepFactory.create(stepCore, null, stepParent);
step = stepRepository.save(step);
itemService.switchVersion(substep, nextVersion);
if (stepCore.getStepNo() == null)
stepParent.appendStep(step);
else
stepParent.addStep(step, stepCore.getStepNo() - 1);
return completeStep(StepMapper.INSTANCE.toDto(substep));
return completeStep(StepMapper.INSTANCE.toDto(step));
}
public StepDto updateStep(long workflowId, long stepId, StepCore updatedStep) {
Step step = checkWorkflowAndStepConsistency(workflowId, stepId);
boolean isSubstep = (step.getWorkflow() == null);
List<Step> ssteps;
if (!isSubstep) {
ssteps = step.getWorkflow().getSteps();
} else {
ssteps = step.getStep().getSubsteps();
}
int numberOfSiblings = ssteps.size();
step = stepValidator.validate(updatedStep, stepId, numberOfSiblings);
itemService.updateInfoDates(step);
itemService.addInformationContributorToItem(step, LoggedInUserHolder.getLoggedInUser());
validateWorkflowAndStepConsistency(workflowId, stepId);
Step prevStep = stepRepository.getOne(stepId);
StepParent parentStep = prevStep.getStepParent();
Item prevVersion = step.getPrevVersion();
Item nextVersion = itemService.clearVersionForUpdate(step);
Step step = stepFactory.create(updatedStep, prevStep, prevStep.getStepParent());
step = stepRepository.save(step);
if (updatedStep.getStepNo() != null) {
int idx = -1;
for (int i = 0; i < numberOfSiblings; i++) {
if (ssteps.get(i).getId().equals(step.getId())) {
idx = i;
break;
}
}
ssteps.remove(idx);
ssteps.add(updatedStep.getStepNo() - 1, step);
if (!isSubstep) {
workflowRepository.save(step.getWorkflow());
} else {
stepRepository.save(step.getStep());
}
parentStep.addStep(step, updatedStep.getStepNo());
}
itemService.switchVersion(prevVersion, nextVersion);
return completeStep(StepMapper.INSTANCE.toDto(step));
}
public void deleteStep(long workflowId, long stepId) {
Step step = checkWorkflowAndStepConsistency(workflowId, stepId);
itemRelatedItemService.deleteRelationsForItem(step);
Item prevVersion = step.getPrevVersion();
Item nextVersion = itemService.clearVersionForDelete(step);
validateWorkflowAndStepConsistency(workflowId, stepId);
Step step = stepRepository.getOne(stepId);
itemService.cleanupItem(step);
stepRepository.delete(step);
itemService.switchVersion(prevVersion, nextVersion);
}
private Step checkWorkflowAndStepConsistency(long workflowId, long stepId) {
if (!workflowRepository.existsById(workflowId)) {
private void validateWorkflowAndStepConsistency(long workflowId, long stepId) {
if (!workflowRepository.existsById(workflowId))
throw new EntityNotFoundException("Unable to find " + Workflow.class.getName() + " with id " + workflowId);
Step step = stepRepository.findById(stepId).orElseThrow(
() -> new EntityNotFoundException("Unable to find " + Step.class.getName() + " with id " + stepId)
);
if (step.getRootWorkflow().getId() != workflowId) {
throw new EntityNotFoundException(
"Unable to find " + Step.class.getName() + " with id " + stepId + " in workflow " + workflowId
);
}
Step step = stepRepository.findById(stepId)
.orElseThrow(() -> new EntityNotFoundException("Unable to find " + Step.class.getName() + " with id " + stepId));
Step s = step;
while (s.getWorkflow() == null) {
s = s.getStep();
}
if (s.getWorkflow().getId() != workflowId) {
throw new EntityNotFoundException("Unable to find " + Step.class.getName() + " with id " + stepId + " in workflow " + workflowId );
}
return step;
}
}
......@@ -5,14 +5,11 @@ import eu.sshopencloud.marketplace.dto.workflows.PaginatedWorkflows;
import eu.sshopencloud.marketplace.dto.workflows.WorkflowCore;
import eu.sshopencloud.marketplace.dto.workflows.WorkflowDto;
import eu.sshopencloud.marketplace.mappers.workflows.WorkflowMapper;
import eu.sshopencloud.marketplace.model.items.Item;
import eu.sshopencloud.marketplace.model.workflows.Workflow;
import eu.sshopencloud.marketplace.repositories.workflows.WorkflowRepository;
import eu.sshopencloud.marketplace.services.auth.LoggedInUserHolder;
import eu.sshopencloud.marketplace.services.items.ItemRelatedItemService;
import eu.sshopencloud.marketplace.services.items.ItemService;
import eu.sshopencloud.marketplace.services.search.IndexService;
import eu.sshopencloud.marketplace.validators.workflows.WorkflowValidator;
import eu.sshopencloud.marketplace.validators.workflows.WorkflowFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
......@@ -32,13 +29,8 @@ import java.util.stream.Collectors;
public class WorkflowService {
private final WorkflowRepository workflowRepository;
private final WorkflowValidator workflowValidator;
private final ItemRelatedItemService itemRelatedItemService;