package eu.eudat.service.dmp; import com.fasterxml.jackson.core.JsonProcessingException; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.Permission; import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.enums.IsActive; import eu.eudat.convention.ConventionService; import eu.eudat.data.DescriptionTemplateEntity; import eu.eudat.data.DmpEntity; import eu.eudat.errorcode.ErrorThesaurusProperties; import eu.eudat.event.DmpTouchedEvent; import eu.eudat.event.EventBroker; import eu.eudat.model.DescriptionTemplate; import eu.eudat.model.Dmp; import eu.eudat.model.builder.DescriptionTemplateBuilder; import eu.eudat.model.builder.DmpBuilder; import eu.eudat.model.deleter.DmpDeleter; import eu.eudat.model.persist.DmpPersist; import eu.eudat.query.DmpQuery; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.deleter.DeleterFactory; import gr.cite.tools.data.query.Ordering; import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyForbiddenException; import gr.cite.tools.exception.MyNotFoundException; import gr.cite.tools.exception.MyValidationException; import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.MapLogEntry; import jakarta.persistence.EntityManager; import jakarta.xml.bind.JAXBException; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.stereotype.Service; import javax.management.InvalidApplicationException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.time.Instant; import java.util.List; import java.util.UUID; @Service public class DmpServiceImpl implements DmpService { private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DmpServiceImpl.class)); private final EntityManager entityManager; private final AuthorizationService authorizationService; private final DeleterFactory deleterFactory; private final BuilderFactory builderFactory; private final QueryFactory queryFactory; private final ConventionService conventionService; private final ErrorThesaurusProperties errors; private final MessageSource messageSource; private final JsonHandlingService jsonHandlingService; private final EventBroker eventBroker; @Autowired public DmpServiceImpl( EntityManager entityManager, AuthorizationService authorizationService, DeleterFactory deleterFactory, BuilderFactory builderFactory, QueryFactory queryFactory, ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, JsonHandlingService jsonHandlingService, EventBroker eventBroker) { this.entityManager = entityManager; this.authorizationService = authorizationService; this.deleterFactory = deleterFactory; this.builderFactory = builderFactory; this.queryFactory = queryFactory; this.conventionService = conventionService; this.errors = errors; this.messageSource = messageSource; this.jsonHandlingService = jsonHandlingService; this.eventBroker = eventBroker; } public Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException { logger.debug(new MapLogEntry("persisting data dmp").And("model", model).And("fields", fields)); this.authorizationService.authorizeForce(Permission.EditDmp); 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()); 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())); return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, Dmp._id), data); } public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException { logger.debug("deleting dmp: {}", id); this.authorizationService.authorizeForce(Permission.DeleteDmp); this.deleterFactory.deleter(DmpDeleter.class).deleteAndSaveByIds(List.of(id)); } @Override public Dmp createNewVersion(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException { logger.debug(new MapLogEntry("persisting data dmp (new version)").And("model", model).And("fields", fields)); this.authorizationService.authorizeForce(Permission.CreateNewVersionDmp); DmpEntity oldDmpEntity = this.entityManager.find(DmpEntity.class, model.getId()); if (oldDmpEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (!this.conventionService.hashValue(oldDmpEntity.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); DmpQuery latestVersionDmpEntityQuery = this.queryFactory.query(DmpQuery.class).groupIds(oldDmpEntity.getGroupId()); latestVersionDmpEntityQuery.setOrder(new Ordering().addDescending(Dmp._version)); DmpEntity latestVersionDmpEntity = latestVersionDmpEntityQuery.first(); if (!latestVersionDmpEntity.getVersion().equals(oldDmpEntity.getVersion())){ //TODO: (THGIANNOS) Create event for version conflict // throw new MyValidationException(this.errors.getDescriptionTemplateNewVersionConflict().getCode(), this.errors.getDescriptionTemplateNewVersionConflict().getMessage()); } DmpEntity data = new DmpEntity(); data.setId(UUID.randomUUID()); data.setIsActive(IsActive.Active); data.setCreatedAt(Instant.now()); data.setUpdatedAt(Instant.now()); data.setGroupId(oldDmpEntity.getGroupId()); data.setVersion((short)(oldDmpEntity.getVersion() + 1)); data.setDescription(model.getDescription()); data.setLabel(model.getLabel()); data.setLanguage(model.getLanguage()); data.setStatus(model.getStatus()); data.setProperties(this.jsonHandlingService.toJsonSafe(model.getProperties())); this.entityManager.persist(data); this.entityManager.flush(); return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, Dmp._id), data); } }