https://github.com/SeelabFhdo/lemma
Raw File
Tip revision: 2e9ccc882352116b253a7700b5ecf2c9316a5829 authored by Florian Rademacher on 24 March 2023, 08:03:13 UTC
Eclipse Launchers: Fix Docker image selection
Tip revision: 2e9ccc8
ServiceModelSourceValidator.kt
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)
        }
    }
}
back to top