package de.fhdo.lemma.model_processing.code_generation.springcloud.domain_events.validators import de.fhdo.lemma.data.ComplexTypeFeature import de.fhdo.lemma.data.DataStructure import de.fhdo.lemma.model_processing.annotations.Before import de.fhdo.lemma.model_processing.annotations.SourceModelValidator import de.fhdo.lemma.model_processing.code_generation.springcloud.domain_events.domainEventsAlias import de.fhdo.lemma.model_processing.languages.convertToAbsoluteFileUrisInPlace import de.fhdo.lemma.model_processing.phases.validation.AbstractXtextModelValidator import de.fhdo.lemma.model_processing.utils.getServiceAspect import de.fhdo.lemma.model_processing.utils.hasInputParameters import de.fhdo.lemma.model_processing.utils.hasResultParameters import de.fhdo.lemma.model_processing.utils.hasServiceAspect import de.fhdo.lemma.service.Operation import de.fhdo.lemma.service.ServiceModel import de.fhdo.lemma.service.ServicePackage import de.fhdo.lemma.technology.CommunicationType import org.eclipse.emf.ecore.resource.Resource import org.eclipse.xtext.validation.Check /** * Validator for service source models. We implement the validation as an Xtext source model validator to take advantage * of LEMMA's Live Validation capabilities. * * @author [Florian Rademacher](mailto:florian.rademacher@fh-dortmund.de) */ @SourceModelValidator internal class ServiceModelSourceValidator : AbstractXtextModelValidator() { override fun getSupportedFileExtensions() = setOf("services") /** * Prepare import model paths before validation */ @Before private fun prepareImportModelPaths(resource: Resource) { val sm = resource.contents[0] as ServiceModel sm.imports.convertToAbsoluteFileUrisInPlace(resource) } /** * Check event producers */ @Check private fun checkProducer(operation: Operation) { val domainEventsAlias = operation.`interface`.microservice.domainEventsAlias ?: return // Operations with the Producer aspect must exhibit a result parameter if (operation.hasServiceAspect(domainEventsAlias, "Producer") && !operation.hasResultParameters(CommunicationType.ASYNCHRONOUS)) error("The Producer aspect may only be applied to operations with a result parameter", ServicePackage.Literals.OPERATION__NAME) } /** * Check event consumers */ @Check private fun checkConsumer(operation: Operation) { val domainEventsAlias = operation.`interface`.microservice.domainEventsAlias ?: return val consumerAspect = operation.getServiceAspect(domainEventsAlias, "Consumer") ?: return // Operations with the Consumer aspect must exhibit an input parameter if (!operation.hasInputParameters(CommunicationType.ASYNCHRONOUS)) { error("The Consumer aspect may only be applied to operations with an input parameter", ServicePackage.Literals.OPERATION__NAME) return } // All parameters of group-events-only consumers must be domain events val groupEventsOnly = consumerAspect.values.find { it.property.name == "groupEventsOnly" }!!.value.asBoolean() if (!groupEventsOnly) return val nonDomainEventParameters = operation.parameters.filterNot { val dataStructureType = it.effectiveType as? DataStructure dataStructureType?.hasFeature(ComplexTypeFeature.DOMAIN_EVENT) ?: false } nonDomainEventParameters.forEach { error("All parameters of group-events-only consumers must be domain events", it, ServicePackage.Literals.PARAMETER__NAME) } } }