Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 53a4977aae138e5b9b4df4062cd14fa7c633de60 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package org.eclipse.etrice.generator.generic

import java.util.List
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.emf.ecore.resource.ResourceSet
import org.eclipse.etrice.core.etmap.eTMap.ETMapFactory
import org.eclipse.etrice.core.etphys.eTPhys.PhysicalModel
import org.eclipse.etrice.core.etphys.eTPhys.PhysicalSystem
import org.eclipse.etrice.core.genmodel.fsm.ILogger
import org.eclipse.etrice.core.room.RoomFactory
import org.eclipse.etrice.core.room.RoomModel
import org.eclipse.etrice.core.room.StructureClass
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
import java.util.Collection
import org.eclipse.emf.common.util.URI

@FinalFieldsConstructor
class TestInstanceCreator {

	static val ANNOTATION_TYPE_NAME = "TestInstance"

	val extension RoomFactory = RoomFactory.eINSTANCE
	val extension ETMapFactory = ETMapFactory.eINSTANCE

	// ctor
	val ILogger logger

	/**
	 * Creates instance and mapping for classes having <code>@TestInstance</code> annotation:
	 * <p>
	 * a) In case of a single SubSystemClass, a new LogicalSystem with a SubSystemRef will be created<br>
	 * b) For ActorClasses, one new SubSystem- and LogicalSystem with necessary refs will be created</br>
	 * Resulting ROOM classes are stored in new RoomModel within a new memory-only resource.</br>
	 * Resulting mapping is stored in a new MappingModel within a new memory-only resource.</br>
	 * </p>
	 * 
	 * Note: currently only one class having <code>@TestInstance</code> annotation is supported
	 * 
	 * @param rs ResourceSet for new resources
	 * @return false, if creation failed and generation should stop
	 */
	def List<Resource> createInstancesAndMapping(Collection<URI> modelsURIs, ResourceSet rs) {
		val roomModels = newArrayList
		val physModels = newArrayList
		rs.resources.forEach[contents.forEach[switch it { 
			RoomModel: if(modelsURIs.contains(eResource.URI)) roomModels += it 
			PhysicalModel: physModels += it
		}]]

		// try find annotated SubSystemClass
		val allTestSubSystems = roomModels.fold(newArrayList, [list, model | 
			list += model.subSystemClasses.filter[hasTestAnnotation] return list
		])
		val List<StructureClass> allAnnotatedClasses = newArrayList(allTestSubSystems)
		val result = newArrayList

		// try find annotated ActorClasses and map them to virtual sub system
		{
			val derivedSubSystem = createSubSystemClass => [name = "DerivedTestSubSystem"]
			roomModels.forEach[model|
				// actors to actorRef into subsystem
				derivedSubSystem.actorRefs += model.actorClasses.filter[hasTestAnnotation].map[ac|
					allAnnotatedClasses += ac
					createActorRef => [
						name = "ref_" + ac.name
						type = ac
					]]]
			if (!derivedSubSystem.actorRefs.isEmpty)
				allTestSubSystems += derivedSubSystem
		}

		if(allTestSubSystems.isEmpty) {
			return result
		}
//		if (roomModels.exists[model|!model.systems.empty]) {
//			allAnnotatedClasses.forEach[roomCls|
//				logger.logInfo(
//					'''TestInstanceCreator: ignored annotation '@«ANNOTATION_TYPE_NAME»' at «roomCls.name»:«roomCls.eClass.name», because there is already a LogicalSystem («roomCls.eResource.URI»)''')]
//			return true
//		}
		
		// validation
		if (allAnnotatedClasses.size > 1) {
			allAnnotatedClasses.forEach[roomCls|
				logger.logError('''TestInstanceCreator: mapping failed, multiple test instances present''', roomCls)]
			return null
		}

		// get physical system
		val List<PhysicalSystem> allPhysSystems = physModels.fold(newArrayList,[list, model|list += model.systems return list])
		if (allPhysSystems.size != 1) {
			logger.logError('''TestInstanceCreator: mapping failed, found «allPhysSystems.size» physical systems''', null)
			return null
		}

		// create mapping
		logger.logInfo('''TestInstanceCreator: creating instance and mapping for «allAnnotatedClasses.head.name»:«allAnnotatedClasses.head.eClass.name»''')
		val physSystem = allPhysSystems.head
		val testSubSystem = allTestSubSystems.head
		val testSystem = createLogicalSystem => [name = "DerivedTestSystem"]
		testSystem.subSystems += createSubSystemRef => [name = "ref_" + testSubSystem.name type = testSubSystem]
		val testRoomModel = createRoomModel => [
			name = "DerivedTestRoomModel"
			systems += testSystem
			if(testSubSystem.eResource === null) subSystemClasses += testSubSystem
		]
		val testMappingModel = createMappingModel => [
			name = "DerivedTestMappingModel"
			mappings += createMapping => [
				logicalSys = testSystem
				physicalSys = physSystem
				subsysMappings += testSystem.subSystems.map [ subSysRef |
					createSubSystemMapping => [
						logicalSubSys = subSysRef
						node = physSystem.nodeRefs.head
					]
				]
			]
		]

		// create memory resource with same uri locations as test instance
		val Resource existingResource = if(testSubSystem.eResource !== null) testSubSystem.eResource else allAnnotatedClasses.head.eResource
		val uriPath = existingResource.URI.trimFileExtension.trimSegments(1)
		var res = rs.createResource(uriPath.appendSegment("DerivedTestMappingModel").appendFileExtension("etmap"))
		res.contents += testMappingModel
		result.add(res)
		res = rs.createResource(uriPath.appendSegment("DerivedTestRoomModel").appendFileExtension("room"))
		res.contents += testRoomModel
		result.add(res)

		return result			
	}

	def protected hasTestAnnotation(StructureClass cls) {
		cls.annotations.exists[type.name == ANNOTATION_TYPE_NAME]
	}
}

Back to the top