Adding reference persisting on dmp persist (work in progress), adding separate persist models for dmp properties

This commit is contained in:
Thomas Georgios Giannos 2023-11-03 16:02:47 +02:00
parent 9cf91aab50
commit 2f20675348
12 changed files with 262 additions and 46 deletions

View File

@ -54,4 +54,14 @@ public class ErrorThesaurusProperties {
public void setDescriptionTemplateNewVersionConflict(ErrorDescription descriptionTemplateNewVersionConflict) { public void setDescriptionTemplateNewVersionConflict(ErrorDescription descriptionTemplateNewVersionConflict) {
DescriptionTemplateNewVersionConflict = descriptionTemplateNewVersionConflict; DescriptionTemplateNewVersionConflict = descriptionTemplateNewVersionConflict;
} }
private ErrorDescription dmpNewVersionConflict;
public ErrorDescription getDmpNewVersionConflict() {
return dmpNewVersionConflict;
}
public void setDmpNewVersionConflict(ErrorDescription dmpNewVersionConflict) {
this.dmpNewVersionConflict = dmpNewVersionConflict;
}
} }

View File

@ -2,9 +2,11 @@ package eu.eudat.model.persist;
import eu.eudat.commons.enums.DmpStatus; import eu.eudat.commons.enums.DmpStatus;
import eu.eudat.commons.validation.ValidId; import eu.eudat.commons.validation.ValidId;
import eu.eudat.model.Reference;
import eu.eudat.model.persist.dmpproperties.DmpPropertiesPersist; import eu.eudat.model.persist.dmpproperties.DmpPropertiesPersist;
import java.time.Instant; import java.time.Instant;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public class DmpPersist { public class DmpPersist {
@ -22,6 +24,8 @@ public class DmpPersist {
private String language; private String language;
private List<ReferencePersist> references;
private String hash; private String hash;
public UUID getId() { public UUID getId() {
@ -72,6 +76,14 @@ public class DmpPersist {
this.language = language; this.language = language;
} }
public List<ReferencePersist> getReferences() {
return references;
}
public void setReferences(List<ReferencePersist> references) {
this.references = references;
}
public String getHash() { public String getHash() {
return hash; return hash;
} }

View File

@ -46,6 +46,8 @@ public class ReferencePersist {
@ValidEnum(message = "{validation.empty}") @ValidEnum(message = "{validation.empty}")
private ReferenceSourceType sourceType; private ReferenceSourceType sourceType;
private String hash;
//private UserInfoPersist createdBy; ToDo //private UserInfoPersist createdBy; ToDo
@ -120,4 +122,12 @@ public class ReferencePersist {
public void setSourceType(ReferenceSourceType sourceType) { public void setSourceType(ReferenceSourceType sourceType) {
this.sourceType = sourceType; this.sourceType = sourceType;
} }
public String getHash() {
return hash;
}
public void setHash(String hash) {
this.hash = hash;
}
} }

View File

@ -21,4 +21,5 @@ public class DmpBlueprintValue {
public void setFieldValue(String fieldValue) { public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue; this.fieldValue = fieldValue;
} }
} }

View File

@ -0,0 +1,35 @@
package eu.eudat.model.persist.dmpproperties;
public class DmpBlueprintValuePersist {
private String fieldId;
private String fieldName;
private String fieldValue;
public String getFieldId() {
return fieldId;
}
public void setFieldId(String fieldId) {
this.fieldId = fieldId;
}
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
}

View File

@ -41,4 +41,5 @@ public class DmpContact {
public void setEmail(String email) { public void setEmail(String email) {
this.email = email; this.email = email;
} }
} }

View File

@ -0,0 +1,45 @@
package eu.eudat.model.persist.dmpproperties;
public class DmpContactPersist {
String userId;
String firstName;
String lastName;
String email;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}

View File

@ -4,23 +4,23 @@ import java.util.List;
public class DmpPropertiesPersist { public class DmpPropertiesPersist {
private List<DmpBlueprintValue> dmpBlueprintValues; private List<DmpBlueprintValuePersist> dmpBlueprintValues;
private List<DmpContact> contacts; private List<DmpContactPersist> contacts;
public List<DmpBlueprintValue> getDmpBlueprintValues() { public List<DmpBlueprintValuePersist> getDmpBlueprintValues() {
return dmpBlueprintValues; return dmpBlueprintValues;
} }
public void setDmpBlueprintValues(List<DmpBlueprintValue> dmpBlueprintValues) { public void setDmpBlueprintValues(List<DmpBlueprintValuePersist> dmpBlueprintValues) {
this.dmpBlueprintValues = dmpBlueprintValues; this.dmpBlueprintValues = dmpBlueprintValues;
} }
public List<DmpContact> getContacts() { public List<DmpContactPersist> getContacts() {
return contacts; return contacts;
} }
public void setContacts(List<DmpContact> contacts) { public void setContacts(List<DmpContactPersist> contacts) {
this.contacts = contacts; this.contacts = contacts;
} }

View File

@ -112,7 +112,7 @@ public class DescriptionTemplateTypeServiceImpl implements DescriptionTemplateTy
} }
public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException { public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException {
logger.debug("deleting dataset: {}", id); logger.debug("deleting descriptionTemplateType: {}", id);
this.authorizationService.authorizeForce(Permission.DeleteDescriptionTemplateType); this.authorizationService.authorizeForce(Permission.DeleteDescriptionTemplateType);

View File

@ -19,7 +19,7 @@ import java.util.UUID;
public interface DmpService { public interface DmpService {
Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException; Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException;
void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException; void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException;

View File

@ -4,20 +4,29 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission; import eu.eudat.authorization.Permission;
import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.XmlHandlingService;
import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.types.reference.DefinitionEntity;
import eu.eudat.commons.types.reference.FieldEntity;
import eu.eudat.convention.ConventionService; import eu.eudat.convention.ConventionService;
import eu.eudat.data.DescriptionTemplateEntity;
import eu.eudat.data.DmpEntity; import eu.eudat.data.DmpEntity;
import eu.eudat.data.DmpReferenceEntity;
import eu.eudat.data.ReferenceEntity;
import eu.eudat.errorcode.ErrorThesaurusProperties; import eu.eudat.errorcode.ErrorThesaurusProperties;
import eu.eudat.event.DmpTouchedEvent; import eu.eudat.event.DmpTouchedEvent;
import eu.eudat.event.EventBroker; import eu.eudat.event.EventBroker;
import eu.eudat.model.DescriptionTemplate;
import eu.eudat.model.Dmp; import eu.eudat.model.Dmp;
import eu.eudat.model.builder.DescriptionTemplateBuilder; import eu.eudat.model.Reference;
import eu.eudat.model.builder.DmpBuilder; import eu.eudat.model.builder.DmpBuilder;
import eu.eudat.model.deleter.DmpDeleter; import eu.eudat.model.deleter.DmpDeleter;
import eu.eudat.model.deleter.ReferenceDeleter;
import eu.eudat.model.persist.DmpPersist; import eu.eudat.model.persist.DmpPersist;
import eu.eudat.model.persist.ReferencePersist;
import eu.eudat.model.persist.referencedefinition.DefinitionPersist;
import eu.eudat.model.persist.referencedefinition.FieldPersist;
import eu.eudat.query.DmpQuery; import eu.eudat.query.DmpQuery;
import eu.eudat.query.DmpReferenceQuery;
import eu.eudat.query.ReferenceQuery;
import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.deleter.DeleterFactory; import gr.cite.tools.data.deleter.DeleterFactory;
@ -33,6 +42,7 @@ import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.JAXBException;
import org.jetbrains.annotations.NotNull;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
@ -43,8 +53,11 @@ import javax.management.InvalidApplicationException;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
@Service @Service
public class DmpServiceImpl implements DmpService { public class DmpServiceImpl implements DmpService {
@ -67,6 +80,8 @@ public class DmpServiceImpl implements DmpService {
private final MessageSource messageSource; private final MessageSource messageSource;
private final XmlHandlingService xmlHandlingService;
private final JsonHandlingService jsonHandlingService; private final JsonHandlingService jsonHandlingService;
private final EventBroker eventBroker; private final EventBroker eventBroker;
@ -80,7 +95,7 @@ public class DmpServiceImpl implements DmpService {
QueryFactory queryFactory, ConventionService conventionService, QueryFactory queryFactory, ConventionService conventionService,
ErrorThesaurusProperties errors, ErrorThesaurusProperties errors,
MessageSource messageSource, MessageSource messageSource,
JsonHandlingService jsonHandlingService, XmlHandlingService xmlHandlingService, JsonHandlingService jsonHandlingService,
EventBroker eventBroker) { EventBroker eventBroker) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
@ -90,49 +105,23 @@ public class DmpServiceImpl implements DmpService {
this.conventionService = conventionService; this.conventionService = conventionService;
this.errors = errors; this.errors = errors;
this.messageSource = messageSource; this.messageSource = messageSource;
this.xmlHandlingService = xmlHandlingService;
this.jsonHandlingService = jsonHandlingService; this.jsonHandlingService = jsonHandlingService;
this.eventBroker = eventBroker; this.eventBroker = eventBroker;
} }
public Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException { public Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException {
logger.debug(new MapLogEntry("persisting data dmp").And("model", model).And("fields", fields)); logger.debug(new MapLogEntry("persisting data dmp").And("model", model).And("fields", fields));
this.authorizationService.authorizeForce(Permission.EditDmp); this.authorizationService.authorizeForce(Permission.EditDmp);
Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); DmpEntity data = this.patchAndSave(model);
DmpEntity data; this.patchAndSave(model.getReferences(), data.getId());
if (isUpdate) {
data = this.entityManager.find(DmpEntity.class, model.getId());
if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale()));
if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage());
} else {
data = new DmpEntity();
data.setId(UUID.randomUUID());
data.setGroupId(UUID.randomUUID());
data.setVersion((short) 1);
data.setIsActive(IsActive.Active);
data.setCreatedAt(Instant.now());
}
data.setLabel(model.getLabel());
data.setStatus(model.getStatus());
try {
data.setProperties(this.jsonHandlingService.toJson(model.getProperties()));
} catch (JsonProcessingException e) {
logger.error(e.getMessage(), e);
}
data.setDescription(model.getDescription());
data.setUpdatedAt(Instant.now());
if (isUpdate)
this.entityManager.merge(data);
else
this.entityManager.persist(data);
this.entityManager.flush();
this.eventBroker.emit(new DmpTouchedEvent(data.getId())); this.eventBroker.emit(new DmpTouchedEvent(data.getId()));
return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, Dmp._id), data);
return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, Dmp._id, Dmp._hash), data);
} }
public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException { public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException {
@ -156,8 +145,7 @@ public class DmpServiceImpl implements DmpService {
latestVersionDmpEntityQuery.setOrder(new Ordering().addDescending(Dmp._version)); latestVersionDmpEntityQuery.setOrder(new Ordering().addDescending(Dmp._version));
DmpEntity latestVersionDmpEntity = latestVersionDmpEntityQuery.first(); DmpEntity latestVersionDmpEntity = latestVersionDmpEntityQuery.first();
if (!latestVersionDmpEntity.getVersion().equals(oldDmpEntity.getVersion())){ if (!latestVersionDmpEntity.getVersion().equals(oldDmpEntity.getVersion())){
//TODO: (THGIANNOS) Create event for version conflict throw new MyValidationException(this.errors.getDmpNewVersionConflict().getCode(), this.errors.getDmpNewVersionConflict().getMessage());
// throw new MyValidationException(this.errors.getDescriptionTemplateNewVersionConflict().getCode(), this.errors.getDescriptionTemplateNewVersionConflict().getMessage());
} }
DmpEntity data = new DmpEntity(); DmpEntity data = new DmpEntity();
@ -180,4 +168,115 @@ public class DmpServiceImpl implements DmpService {
return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, Dmp._id), data); return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, Dmp._id), data);
} }
private DmpEntity patchAndSave(DmpPersist model) throws JsonProcessingException {
Boolean isUpdate = this.conventionService.isValidGuid(model.getId());
DmpEntity data;
if (isUpdate) {
data = this.entityManager.find(DmpEntity.class, model.getId());
if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale()));
if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage());
} else {
data = new DmpEntity();
data.setId(UUID.randomUUID());
data.setGroupId(UUID.randomUUID());
data.setVersion((short) 1);
data.setIsActive(IsActive.Active);
data.setCreatedAt(Instant.now());
}
data.setLabel(model.getLabel());
data.setStatus(model.getStatus());
data.setProperties(this.jsonHandlingService.toJson(model.getProperties()));
data.setDescription(model.getDescription());
data.setUpdatedAt(Instant.now());
if (isUpdate)
this.entityManager.merge(data);
else
this.entityManager.persist(data);
this.entityManager.flush();
return data;
}
private void patchAndSave(List<ReferencePersist> models, UUID dmpId) throws InvalidApplicationException {
if (models == null || models.isEmpty())
return;
List<DmpReferenceEntity> references = this.queryFactory.query(DmpReferenceQuery.class).dmpIds(dmpId).collect();
Map<UUID, List<DmpReferenceEntity>> referencesLookup = this.conventionService.toDictionaryOfList(references, DmpReferenceEntity::getDmpId);
List<ReferenceEntity> existingReferences;
if (referencesLookup.containsKey(dmpId))
existingReferences = this.queryFactory.query(ReferenceQuery.class).ids(referencesLookup.get(dmpId).stream().map(DmpReferenceEntity::getId).toList()).collect();
else
existingReferences = new ArrayList<>();
List<UUID> updatedReferencesIds = models.stream().map(ReferencePersist::getId).filter(this.conventionService::isValidGuid).distinct().toList();
List<ReferenceEntity> toDelete = existingReferences.stream().filter(x -> !updatedReferencesIds.contains(x.getId())).toList();
this.deleterFactory.deleter(ReferenceDeleter.class).delete(toDelete);
Map<UUID, ReferenceEntity> existingReferencesLookup = existingReferences.stream().collect(Collectors.toMap(ReferenceEntity::getId, x -> x));
for (ReferencePersist model : models) {
Boolean isUpdate = this.conventionService.isValidGuid(model.getId());
ReferenceEntity data;
if (isUpdate) {
if (!existingReferencesLookup.containsKey(model.getId()))
throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Reference.class.getSimpleName()}, LocaleContextHolder.getLocale()));
data = existingReferencesLookup.get(model.getId());
if (data == null)
throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Reference.class.getSimpleName()}, LocaleContextHolder.getLocale()));
if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash()))
throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage());
} else {
data = new ReferenceEntity();
data.setId(UUID.randomUUID());
data.setIsActive(IsActive.Active);
data.setCreatedAt(Instant.now());
}
data.setDefinition(this.xmlHandlingService.toXmlSafe(this.buildDefinitionEntity(model.getDefinition())));
data.setUpdatedAt(Instant.now());
data.setReference(model.getReference());
data.setAbbreviation(model.getAbbreviation());
data.setSource(model.getSource());
data.setSourceType(model.getSourceType());
if (isUpdate)
this.entityManager.merge(data);
else
this.entityManager.persist(data);
}
this.entityManager.flush();
}
private @NotNull DefinitionEntity buildDefinitionEntity(DefinitionPersist persist){
DefinitionEntity data = new DefinitionEntity();
if (persist == null) return data;
if (!this.conventionService.isListNullOrEmpty(persist.getFields())){
data.setFields(new ArrayList<>());
for (FieldPersist fieldPersist: persist.getFields()) {
data.getFields().add(this.buildFieldEntity(fieldPersist));
}
}
return data;
}
private @NotNull FieldEntity buildFieldEntity(FieldPersist persist){
FieldEntity data = new FieldEntity();
if (persist == null) return data;
data.setCode(persist.getCode());
data.setDataType(persist.getDataType());
data.setCode(persist.getCode());
return data;
}
} }

View File

@ -29,3 +29,6 @@ error-thesaurus:
description-template-new-version-conflict: description-template-new-version-conflict:
code: 114 code: 114
message: version to update not the latest message: version to update not the latest
dmp-new-version-conflict:
code: 115
message: version to update not the latest