Skip to content

Exercise 1

The main objective of this exercise is to convert the flowchart model’s name into the name of a valid HEAD element (in HTML) i.e., the HEAD element is part of a valid HTML document.

Input Model

Source model representing the flowchart instance (in XMI format) conforming to the flowchart domain is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<flowchart:Flowchart xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowchart="flowchart" xmi:id="_9mLMwDY6EeOwt8pm-kjW_Q" name="Wakeup">
  <nodes xsi:type="flowchart:Action" xmi:id="_9mLMwTY6EeOwt8pm-kjW_Q" name="Wake up" outgoing="_9mLMxjY6EeOwt8pm-kjW_Q" incoming="_9mLMyDY6EeOwt8pm-kjW_Q _9mLz0TY6EeOwt8pm-kjW_Q"/>
  <nodes xsi:type="flowchart:Decision" xmi:id="_9mLMwjY6EeOwt8pm-kjW_Q" name="Is it really too early?" outgoing="_9mLMxzY6EeOwt8pm-kjW_Q _9mLz0DY6EeOwt8pm-kjW_Q" incoming="_9mLMxjY6EeOwt8pm-kjW_Q"/>
  <nodes xsi:type="flowchart:Action" xmi:id="_9mLMwzY6EeOwt8pm-kjW_Q" name="Sleep" outgoing="_9mLMyDY6EeOwt8pm-kjW_Q" incoming="_9mLMxzY6EeOwt8pm-kjW_Q"/>
  <nodes xsi:type="flowchart:Action" xmi:id="_9mLMxDY6EeOwt8pm-kjW_Q" name="Get up" incoming="_9mLz0DY6EeOwt8pm-kjW_Q"/>
  <nodes xsi:type="flowchart:Action" xmi:id="_9mLMxTY6EeOwt8pm-kjW_Q" name="begin" outgoing="_9mLz0TY6EeOwt8pm-kjW_Q"/>
  <transitions xmi:id="_9mLMxjY6EeOwt8pm-kjW_Q" name="" source="_9mLMwTY6EeOwt8pm-kjW_Q" target="_9mLMwjY6EeOwt8pm-kjW_Q"/>
  <transitions xmi:id="_9mLMxzY6EeOwt8pm-kjW_Q" name="Yes" source="_9mLMwjY6EeOwt8pm-kjW_Q" target="_9mLMwzY6EeOwt8pm-kjW_Q"/>
  <transitions xmi:id="_9mLMyDY6EeOwt8pm-kjW_Q" name="Some Time Passes" source="_9mLMwzY6EeOwt8pm-kjW_Q" target="_9mLMwTY6EeOwt8pm-kjW_Q"/>
  <transitions xmi:id="_9mLz0DY6EeOwt8pm-kjW_Q" name="No" source="_9mLMwjY6EeOwt8pm-kjW_Q" target="_9mLMxDY6EeOwt8pm-kjW_Q"/>
  <transitions xmi:id="_9mLz0TY6EeOwt8pm-kjW_Q" name="start" source="_9mLMxTY6EeOwt8pm-kjW_Q" target="_9mLMwTY6EeOwt8pm-kjW_Q"/>
</flowchart:Flowchart>

Expected Output Model

<?xml version="1.0" encoding="ISO-8859-1"?>
<HTML xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="HTML">
  <head value="Wakeup"/>
</HTML>

Task

The base transformation below contains an input and output pattern. You must add another output pattern (.out) which has an object name “html” and object type “HTML”. The lambda expression must set the ‘head’ attribute of the ‘html’ object as the object name ‘head’ (previously defined in the first output pattern).

Base Transformation

Transformation class containing the MT definition. All rules are defined in the ruleStore().

package flowchartToHtmlExamples
import static yamtl.dsl.Rule.*

import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.EPackage

import yamtl.core.YAMTLModule
import yamtl.groovy.YAMTLGroovyExtensions
import yamtl.groovy.YAMTLGroovyExtensions_dynamicEMF

class Example1 extends YAMTLModule {
    public Example1(EPackage flowchartPk, EPackage htmlPk) {
        YAMTLGroovyExtensions_dynamicEMF.init(this)

        header().in("in", flowchartPk).out("out", htmlPk)

        ruleStore([
                rule('FlowchartName2Head')
                        .in("flowchart", flowchartPk.Flowchart)
                        .out("head", htmlPk.HEAD, {             
                            head.value = flowchart.name
                        })
                        //TODO: Add another output object here

        ])

    }
}

Test Script

This is a separate Groovy class that loads, executes and tests the model transformation. In particular, the source and target metamodels are loaded and passed to the transformation class. Then, the input model is loaded into this class and executed. Thus, creating an output model which is stored and tested for correctness.

package flowchartToHtmlExamples
import static org.junit.Assert.assertTrue;
import org.junit.jupiter.api.Test
import yamtl.core.YAMTLModule
import yamtl.groovy.YAMTLGroovyExtensions
import yamtl.utils.EMFComparator

class Example2Test extends YAMTLModule {
    final BASE_PATH = 'model'

    @Test
    def void testExample2() {
        // model transformation execution
        def srcRes = YAMTLModule.preloadMetamodel(BASE_PATH + '/flowchart.ecore')
        def tgtRes = YAMTLModule.preloadMetamodel(BASE_PATH + '/html.ecore')

        def xform = new Example2(srcRes.contents[0], tgtRes.contents[0])
        YAMTLGroovyExtensions.init(this)
        xform.loadInputModels(['in': BASE_PATH + '/wakeup.xmi'])
        xform.execute()
        xform.saveOutputModels(['out': BASE_PATH + '/example2Output.xmi'])

        // test assertion
        def actualModel = xform.getOutputModel('out')
        EMFComparator comparator = new EMFComparator();

        // Load the expected model using the identical output metamodel from the transformation.
        // Essentially, use the same in-memory metamodel.
        xform.loadMetamodelResource(tgtRes)
        def expectedResource = xform.loadModel(BASE_PATH + '/example2ExpectedOutput.xmi', false)
        def assertionResult =  comparator.equals(expectedResource.getContents(), actualModel.getContents())
        assertTrue(assertionResult);
    }
}

Last update: October 13, 2023