Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 0d6d8e229fab573ad1179b21c1c5d6471c39a4a5 (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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
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.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
import org.eclipse.etrice.generator.base.logging.ILogger
import org.eclipse.etrice.core.genmodel.fsm.IDiagnostician
import org.eclipse.etrice.core.room.SubSystemClass
import org.eclipse.etrice.core.room.ActorClass
import org.eclipse.etrice.core.etphys.eTPhys.ETPhysFactory
import org.eclipse.etrice.core.etphys.eTPhys.ThreadModel
import org.eclipse.etrice.core.etphys.eTPhys.ExecMode

@FinalFieldsConstructor
class TestInstanceCreator {

	static val ANNOTATION_TYPE_NAME = "TestInstance"

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

	// ctor
	val ILogger logger
	val IDiagnostician diagnostician

	/**
	 * 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.roomClasses.filter(SubSystemClass).filter[hasTestAnnotation] return list
		])
		val List<StructureClass> allAnnotatedClasses = newArrayList(allTestSubSystems)

		// 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.roomClasses.filter(ActorClass).filter[hasTestAnnotation].map[ac|
					allAnnotatedClasses += ac
					createActorRef => [
						name = "ref_" + ac.name
						type = ac
					]]]
			if (!derivedSubSystem.actorRefs.isEmpty)
				allTestSubSystems += derivedSubSystem
		}

		if(allTestSubSystems.isEmpty) {
			return emptyList
		}
//		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|
				diagnostician.error('''TestInstanceCreator: mapping failed, multiple test instances present''', roomCls, null)]
			return null
		}

		// get physical system
		val List<PhysicalSystem> allPhysSystems = physModels.fold(newArrayList,[list, model|list += model.systems return list])
		if(allPhysSystems.size == 0) {	// add a default physical system if none is present
			allPhysSystems.add(createDefaultPhysicalSystem)
		}
		else if (allPhysSystems.size > 1) {
			logger.logError('''TestInstanceCreator: mapping failed, found «allPhysSystems.size» physical systems''')
			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"
			roomClasses += testSystem
			if(testSubSystem.eResource === null) roomClasses += 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)
		val etmapRes = rs.createResource(uriPath.appendSegment("DerivedTestMappingModel").appendFileExtension("etmap"))
		etmapRes.contents += testMappingModel
		val roomRes = rs.createResource(uriPath.appendSegment("DerivedTestRoomModel").appendFileExtension("room"))
		roomRes.contents += testRoomModel

		return #[etmapRes, roomRes]			
	}

	def protected hasTestAnnotation(StructureClass cls) {
		cls.annotations.exists[type.name == ANNOTATION_TYPE_NAME]
	}
	
	def private createDefaultPhysicalSystem() {
		val runtimeClass = createRuntimeClass => [
			name = "DefaultRuntimeClass"
			threadModel = ThreadModel.MULTI_THREADED
		]
		val nodeClass = createNodeClass => [
			runtime = runtimeClass
			priomin = 1
			priomax = 10
			threads += createPhysicalThread => [
				name = "DefaultPhysicalThread"
				^default = true
				execmode = ExecMode.MIXED
				time = 100
				prio = 5
				stacksize = 1024
				msgblocksize = 64
				msgpoolsize = 100
			]
		]
		createPhysicalSystem => [
			name = "GenericPhysicalSystem"
			nodeRefs += createNodeRef => [
				name = "node"
				type = nodeClass
			]
		]
	}
}

Back to the top