package eu.eudat.service.reference; import com.fasterxml.jackson.core.JsonProcessingException; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.Permission; import eu.eudat.commons.XmlHandlingService; import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.ReferenceFieldDataType; import eu.eudat.commons.enums.ReferenceSourceType; import eu.eudat.commons.types.reference.DefinitionEntity; import eu.eudat.commons.types.reference.FieldEntity; import eu.eudat.commons.types.referencetype.*; import eu.eudat.convention.ConventionService; import eu.eudat.data.ReferenceEntity; import eu.eudat.data.ReferenceTypeEntity; import eu.eudat.data.TenantEntityManager; import eu.eudat.model.Reference; import eu.eudat.model.ReferenceType; import eu.eudat.model.builder.ReferenceBuilder; import eu.eudat.model.deleter.ReferenceDeleter; import eu.eudat.model.persist.ReferencePersist; import eu.eudat.model.persist.referencedefinition.DefinitionPersist; import eu.eudat.model.persist.referencedefinition.FieldPersist; import eu.eudat.query.ReferenceQuery; import eu.eudat.query.lookup.ReferenceSearchLookup; import eu.eudat.service.externalfetcher.ExternalFetcherService; import eu.eudat.service.externalfetcher.config.entities.SourceBaseConfiguration; import eu.eudat.service.externalfetcher.criteria.ExternalReferenceCriteria; import eu.eudat.service.externalfetcher.models.ExternalDataResult; 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.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.jetbrains.annotations.NotNull; import org.slf4j.LoggerFactory; 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.*; import java.util.stream.Collectors; @Service public class ReferenceServiceImpl implements ReferenceService { private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(ReferenceServiceImpl.class)); private final TenantEntityManager entityManager; private final AuthorizationService authorizationService; private final DeleterFactory deleterFactory; private final BuilderFactory builderFactory; private final ConventionService conventionService; private final MessageSource messageSource; private final QueryFactory queryFactory; private final XmlHandlingService xmlHandlingService; public final ExternalFetcherService externalFetcherService; public ReferenceServiceImpl( TenantEntityManager entityManager, AuthorizationService authorizationService, DeleterFactory deleterFactory, BuilderFactory builderFactory, ConventionService conventionService, MessageSource messageSource, QueryFactory queryFactory, XmlHandlingService xmlHandlingService, ExternalFetcherService externalFetcherService) { this.entityManager = entityManager; this.authorizationService = authorizationService; this.deleterFactory = deleterFactory; this.builderFactory = builderFactory; this.conventionService = conventionService; this.messageSource = messageSource; this.queryFactory = queryFactory; this.xmlHandlingService = xmlHandlingService; this.externalFetcherService = externalFetcherService; } @Override public Reference persist(ReferencePersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, JsonProcessingException, TransformerException, ParserConfigurationException { logger.debug(new MapLogEntry("persisting data").And("model", model).And("fields", fields)); this.authorizationService.authorizeForce(Permission.EditReference); Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); ReferenceEntity data; if (isUpdate) { data = this.entityManager.find(ReferenceEntity.class, model.getId()); if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Reference.class.getSimpleName()}, LocaleContextHolder.getLocale())); } else { data = new ReferenceEntity(); data.setId(UUID.randomUUID()); data.setIsActive(IsActive.Active); data.setCreatedAt(Instant.now()); } data.setLabel(model.getLabel()); data.setTypeId(model.getTypeId()); data.setDescription(model.getDescription()); 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(); return this.builderFactory.builder(ReferenceBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, Reference._id), data); } 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.setValue(persist.getValue()); return data; } @Override public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException { logger.debug("deleting : {}", id); this.authorizationService.authorizeForce(Permission.DeleteReference); this.deleterFactory.deleter(ReferenceDeleter.class).deleteAndSaveByIds(List.of(id)); } @Override public List searchReferenceData(ReferenceSearchLookup lookup) throws MyNotFoundException, InvalidApplicationException { int initialOffset = 0; if (lookup.getPage() != null && !lookup.getPage().isEmpty()){ initialOffset = lookup.getPage().getOffset(); lookup.getPage().setOffset(0); } ReferenceTypeEntity data = this.entityManager.find(ReferenceTypeEntity.class, lookup.getTypeId()); if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{lookup.getTypeId(), ReferenceType.class.getSimpleName()}, LocaleContextHolder.getLocale())); String like; if (lookup.getLike() != null){ like = lookup.getLike().replaceAll("%", ""); } else { like = null; } ExternalReferenceCriteria externalReferenceCriteria = new ExternalReferenceCriteria(like, lookup.getDependencyReferences()); ExternalDataResult remoteRepos = this.getReferenceData(data, externalReferenceCriteria, lookup.getKey()); List externalModels = new ArrayList<>(); if (remoteRepos != null && !this.conventionService.isListNullOrEmpty(remoteRepos.getResults())){ List referenceEntities = new ArrayList<>(); for (Map result : remoteRepos.getResults()){ if (result == null || result.isEmpty()) continue;; ReferenceEntity referenceEntity = buildReferenceEntityFromExternalData(result, data); referenceEntities.add(referenceEntity); } externalModels = this.builderFactory.builder(ReferenceBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(lookup.getProject(), referenceEntities); } List models = this.fetchReferenceFromDb(lookup); models.addAll(externalModels); models = models.stream().sorted(Comparator.comparing(Reference::getLabel, Comparator.nullsFirst(Comparator.naturalOrder()))).collect(Collectors.toList()); if (lookup.getPage() != null && !lookup.getPage().isEmpty()){ models = models.stream().skip(initialOffset).limit(lookup.getPage().getSize()).toList(); } return models; } @NotNull private ReferenceEntity buildReferenceEntityFromExternalData(Map result, ReferenceTypeEntity data) { ReferenceEntity referenceEntity = new ReferenceEntity(); referenceEntity.setTypeId(data.getId()); referenceEntity.setIsActive(IsActive.Active); referenceEntity.setReference(result.getOrDefault(ReferenceEntity.KnownFields.ReferenceId, null)); referenceEntity.setSource(result.getOrDefault(ReferenceEntity.KnownFields.Key, null)); referenceEntity.setAbbreviation(result.getOrDefault(ReferenceEntity.KnownFields.Abbreviation, null)); referenceEntity.setDescription(result.getOrDefault(ReferenceEntity.KnownFields.Description, null)); referenceEntity.setLabel(result.getOrDefault(ReferenceEntity.KnownFields.Label, null)); referenceEntity.setSourceType(ReferenceSourceType.External); DefinitionEntity definitionEntity = new DefinitionEntity(); definitionEntity.setFields(new ArrayList<>()); for (Map.Entry resultValue : result.entrySet()){ if (resultValue.getKey().equals(ReferenceEntity.KnownFields.ReferenceId) || resultValue.getKey().equals(ReferenceEntity.KnownFields.Abbreviation) || resultValue.getKey().equals(ReferenceEntity.KnownFields.Description) || resultValue.getKey().equals(ReferenceEntity.KnownFields.Label) || resultValue.getKey().equals(ReferenceEntity.KnownFields.SourceLabel)) continue; FieldEntity fieldEntity = new FieldEntity(); fieldEntity.setCode(resultValue.getKey()); fieldEntity.setValue(resultValue.getValue()); fieldEntity.setDataType(ReferenceFieldDataType.Text); definitionEntity.getFields().add(fieldEntity); } if (!definitionEntity.getFields().isEmpty()) referenceEntity.setDefinition(this.xmlHandlingService.toXmlSafe(definitionEntity)); return referenceEntity; } private List fetchReferenceFromDb(ReferenceSearchLookup lookup){ ReferenceQuery query = lookup.enrich(this.queryFactory).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).sourceTypes(ReferenceSourceType.Internal).typeIds(lookup.getTypeId()); List data = query.collectAs(lookup.getProject()); return this.builderFactory.builder(ReferenceBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(lookup.getProject(), data); } private ExternalDataResult getReferenceData(ReferenceTypeEntity referenceType, ExternalReferenceCriteria externalReferenceCriteria, String key) { ReferenceTypeDefinitionEntity referenceTypeDefinition = this.xmlHandlingService.fromXmlSafe(ReferenceTypeDefinitionEntity.class, referenceType.getDefinition()); if (referenceTypeDefinition == null || this.conventionService.isListNullOrEmpty(referenceTypeDefinition.getSources())) return new ExternalDataResult(); ExternalDataResult results = this.externalFetcherService.getExternalData(referenceTypeDefinition.getSources().stream().map(x -> (SourceBaseConfiguration)x).collect(Collectors.toList()), externalReferenceCriteria, key); for (Map result: results.getResults()) { result.put("referenceType", referenceType.getName()); } return results; } }