Newer
Older
package org.etsi.mts.tdl.to2tdl;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.etsi.mts.tdl.Comment;
import org.etsi.mts.tdl.ComponentInstance;
import org.etsi.mts.tdl.ComponentInstanceRole;
import org.etsi.mts.tdl.ComponentType;
import org.etsi.mts.tdl.CompoundBehaviour;
import org.etsi.mts.tdl.Connection;
import org.etsi.mts.tdl.DataInstanceUse;
import org.etsi.mts.tdl.GateInstance;
import org.etsi.mts.tdl.GateReference;
import org.etsi.mts.tdl.GateType;
import org.etsi.mts.tdl.LiteralValueUse;
import org.etsi.mts.tdl.Member;
import org.etsi.mts.tdl.Message;
import org.etsi.mts.tdl.Package;
import org.etsi.mts.tdl.StructuredDataType;
import org.etsi.mts.tdl.Target;
import org.etsi.mts.tdl.TestConfiguration;
import org.etsi.mts.tdl.TestDescription;
import org.etsi.mts.tdl.tdlFactory;
import org.etsi.mts.tdl.tdlPackage;
import org.etsi.mts.tdl.helper.TDLHelper;
import org.etsi.mts.tdl.structuredobjectives.Content;
import org.etsi.mts.tdl.structuredobjectives.DataReference;
import org.etsi.mts.tdl.structuredobjectives.EntityReference;
import org.etsi.mts.tdl.structuredobjectives.EventOccurrenceSpecification;
import org.etsi.mts.tdl.structuredobjectives.LiteralValue;
import org.etsi.mts.tdl.structuredobjectives.StructuredTestObjective;
import org.etsi.mts.tdl.structuredobjectives.Value;
import org.etsi.mts.tdl.transform.AbstractTranslator;
public class TO2TDLTranslator extends AbstractTranslator {
public void transform(Package p) {
List<StructuredTestObjective> stos = EcoreUtil2.getAllContentsOfType(p, StructuredTestObjective.class);
//TODO: difficult to read, unless broken into sub-packages
// for (var sto : stos) {
// transform(sto);
// }
//TODO: add validation both as pre-check option and in transformation logging
//TODO: extract generic and specific functionality
//specific can be customised for different configurations but also for differnet inputs
//broken into separate iterations for readability
for (StructuredTestObjective sto : stos) {
transformData(sto);
}
//TODO: in case split even further
for (StructuredTestObjective sto : stos) {
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
transformConfiguration(sto);
transformBehaviour(sto);
}
// for (var sto : stos) {
// transformBehaviour(sto);
// }
}
private void transform(StructuredTestObjective sto) {
//TODO: break down into packages? or rearrange later?
System.out.println(sto.getName());
transformData(sto);
transformConfiguration(sto);
transformBehaviour(sto);
}
private void transformBehaviour(StructuredTestObjective sto) {
List<EntityReference> ers = EcoreUtil2.getAllContentsOfType(sto, EntityReference.class);
String configurationName = getConfigurationName(ers);
TestConfiguration configuration = getTypeFor(configurationName , tdlPackage.Literals.TEST_CONFIGURATION);
TestDescription td = getTypeFor("TD_"+sto.getName(), tdlPackage.Literals.TEST_DESCRIPTION);
td.setTestConfiguration(configuration);
td.getTestObjective().add(sto);
td.setBehaviourDescription(tdlFactory.eINSTANCE.createBehaviourDescription());
CompoundBehaviour topLevelBehaviour = tdlFactory.eINSTANCE.createCompoundBehaviour();
topLevelBehaviour.setBlock(tdlFactory.eINSTANCE.createBlock());
td.getBehaviourDescription().setBehaviour(topLevelBehaviour);
//TODO: for all event occurrences -> done
//TODO: add designated blocks? especially for new syntax...
//TODO: messages vs procedures?
//TODO: also repeated?
//TODO: also variants?
//TODO: also templates?
//TODO: direction based on verbs and/or qualifiers
List<EventOccurrenceSpecification> eos = EcoreUtil2.getAllContentsOfType(sto, EventOccurrenceSpecification.class);
for (EventOccurrenceSpecification eo : eos) {
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
Message message = transformMessage(eo, configuration);
topLevelBehaviour.getBlock().getBehaviour().add(message);
}
//TODO: what about more abstract behaviours, e.g. establish connection, close connection, etc.
// -> is it the case to generate / use "keyword" based approach
// where TDs/functions are generated / referenced for each event
// -> an option can then inline the referenced functions (or even keep them separate?)
// -> using sub-configurations with mappings can add further indirection/flexibility but may be too much overhead
// -> the main configuration can then even be composed from the sub configurations using part 7 (even more overhead)
// -> a construct may be needed to link an event to a TD
// -> alternatively annotations can be used, but a structured approach can be useful for traceability as well
//TODO: what about negative behaviours? e.g. not closes / does not close?
}
private Message transformMessage(EventOccurrenceSpecification eo, TestConfiguration configuration) {
Message message = tdlFactory.eINSTANCE.createMessage();
//TODO: resolve gate references properly -> done
//TODO: check event type to determine direction
ComponentInstance source = getContentWithName(eo.getEntityReference().getEntity().getName(), configuration, ComponentInstance.class).get();
ComponentInstance target;
if (!eo.getOppositeEntityReference().isEmpty()) {
//TODO: handle multiple targets?
target = getContentWithName(eo.getOppositeEntityReference().get(0).getEntity().getName(), configuration, ComponentInstance.class).get();
} else {
target = getContentWithName(source.getName()+"_Tester", configuration, ComponentInstance.class).get();
}
Connection connection = getConnectionBetween(source, target, configuration).get();
System.out.println("Connection between: "+source.getName() + " and "+target.getName());
//TODO: check order of gate references -> done
GateReference sg;
GateReference tg;
if (connection.getEndPoint().get(0).getComponent()==source) {
sg = connection.getEndPoint().get(0);
tg = connection.getEndPoint().get(1);
} else {
sg = connection.getEndPoint().get(1);
tg = connection.getEndPoint().get(0);
}
System.out.println(" -> Interaction between: "+sg.getComponent().getName() + " and "+tg.getComponent().getName());
System.out.println(" For event: " + NodeModelUtils.getNode(eo).getText());
//TODO: remove default gates once issue has been solved
//sg = configuration.getConnection().get(0).getEndPoint().get(0);
//tg = configuration.getConnection().get(0).getEndPoint().get(1);
message.setSourceGate(sg);
Target targets = tdlFactory.eINSTANCE.createTarget();
message.getTarget().add(targets);
targets.setTargetGate(tg);
Philip Makedonski
committed
if (eo.getEventReference().getEvent().getName().contains("receiv")) {
message.setSourceGate(tg);
targets.setTargetGate(sg);
}
//TODO: resolve arguments properly
LiteralValueUse du = tdlFactory.eINSTANCE.createLiteralValueUse();
if (eo.getEventArgument()!=null) {
Philip Makedonski
committed
du.setValue("\""+NodeModelUtils.getNode(eo.getEventArgument()).getText().replaceAll("\"", "\\\\\"")+"\"");
} else {
du.setValue("\"TODO: Empty argument?\"");
}
message.setArgument(du);
//TODO: for debugging
Comment debug = tdlFactory.eINSTANCE.createComment();
Philip Makedonski
committed
debug.setBody("\"Event: "+NodeModelUtils.getNode(eo).getText().replaceAll("\"", "\\\\\"")+"\"");
message.getComment().add(debug);
return message;
}
private void transformData(StructuredTestObjective sto) {
List<EventOccurrenceSpecification> eos = EcoreUtil2.getAllContentsOfType(sto, EventOccurrenceSpecification.class);
for (EventOccurrenceSpecification eo : eos) {
if (eo.getEventArgument() instanceof LiteralValue) {
transform((LiteralValue) eo.getEventArgument());
}
//TODO: handle predefined values and other arguments
}
}
private void transformConfiguration(StructuredTestObjective sto) {
//TODO: infer from all participating entities in the TP
// collect all participating entities for the TP
// generate name based on sorted entities
// infer connections based on interactions (bi-directional)
// assumptions:
// - one default gate per component
// - if no opposite entity, assumed tester (or other entity if only two entities)
// - for every event occurrence check if a connection exists and create otherwise
List<EventOccurrenceSpecification> eos = EcoreUtil2.getAllContentsOfType(sto, EventOccurrenceSpecification.class);
boolean oldWay = false;
if (oldWay) {
for (EventOccurrenceSpecification eo : eos) {
//TODO: summarise workflow for all steps
transform(eo.getEntityReference());
if (!eo.getOppositeEntityReference().isEmpty()) {
//TODO: handle opposite entity references
for (EntityReference oe : eo.getOppositeEntityReference()) {
transform(oe);
}
} else {
//TODO: consider using the same type instead!?
transform(eo.getEntityReference(), "_Tester");
}
//TODO: create configuration
transformConfiguration(eo);
}
}
//Component and Gate Types
List<EntityReference> ers = EcoreUtil2.getAllContentsOfType(sto, EntityReference.class);
transform(er);
}
//Test Configuration
String configurationName = getConfigurationName(ers);
TestConfiguration configuration = getTypeFor(configurationName , tdlPackage.Literals.TEST_CONFIGURATION);
//Component Instances
transformComponentInstance(configuration, er);
}
//Connections and Implicit Testers?
for (EventOccurrenceSpecification eo : eos) {
ComponentInstance i = getContentWithName(eo.getEntityReference().getEntity().getName(), configuration, ComponentInstance.class).get();
if (!eo.getOppositeEntityReference().isEmpty()) {
//Opposite entity references
for (EntityReference oe : eo.getOppositeEntityReference()) {
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
ComponentInstance opposite = getContentWithName(oe.getEntity().getName(), configuration, ComponentInstance.class).get();
transformConnection(configuration, i, opposite);
}
} else {
//TODO: Implicit tester?
//TODO: check also type of event
transformComponentInstance(configuration, eo.getEntityReference(), "_Tester");
ComponentInstance opposite = getContentWithName(eo.getEntityReference().getEntity().getName()+"_Tester", configuration, ComponentInstance.class).get();
transformConnection(configuration, i, opposite);
}
}
//TODO: for debugging
String body = "\"See "+sto.getName()+"\"";
Comment source = tdlFactory.eINSTANCE.createComment();
source.setBody(body);
configuration.getComment().add(source);
}
private String getConfigurationName(List<EntityReference> ers) {
Set<String> participatingEntityNames = ers.stream()
.map(e->e.getEntity().getName())
.sorted()
.collect(Collectors.toSet());
String configurationName = "TC_"+String.join("_", participatingEntityNames);
return configurationName;
}
private void transformComponentInstance(TestConfiguration configuration, EntityReference er) {
transformComponentInstance(configuration, er, "");
}
private void transformComponentInstance(TestConfiguration configuration, EntityReference er, String suffix) {
String componentTypeName = er.getEntity().getName()+"_Type";
String instanceName = er.getEntity().getName()+suffix;
ComponentType componentType = getTypeFor(componentTypeName, tdlPackage.Literals.COMPONENT_TYPE);
Optional<ComponentInstance> optional = getContentWithName(instanceName, configuration, ComponentInstance.class);
ComponentInstance i;
if (optional.isPresent()) {
i = optional.get();
} else {
i = (ComponentInstance) tdlFactory.eINSTANCE.create(tdlPackage.Literals.COMPONENT_INSTANCE);
i.setName(instanceName);
i.setType(componentType);
//TODO: check entity type to assign role
//TODO: alternatively based on naming or other criteria?
//TODO: log assumptions
//name-based
if (instanceName.equals("IUT") || instanceName.equals("SUT")) {
i.setRole(ComponentInstanceRole.SUT);
} else {
i.setRole(ComponentInstanceRole.TESTER);
}
if (instanceName.contains("Tester")) {
i.setRole(ComponentInstanceRole.TESTER);
}
configuration.getComponentInstance().add(i);
}
}
private void transformConfiguration(EventOccurrenceSpecification eo) {
String componentTypeName = eo.getEntityReference().getEntity().getName()+"_Type";
if (!eo.getOppositeEntityReference().isEmpty()) {
//TODO: handle opposite entity references
for (EntityReference oe : eo.getOppositeEntityReference()) {
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
//transform(oe);
}
} else {
String configurationName = componentTypeName + "_" + componentTypeName + "_Tester";
TestConfiguration configuration = getTypeFor(configurationName , tdlPackage.Literals.TEST_CONFIGURATION);
transformComponentInstance(configuration, eo.getEntityReference());
transformComponentInstance(configuration, eo.getEntityReference(), "_Tester");
ComponentInstance i = getContentWithName(eo.getEntityReference().getEntity().getName(), configuration, ComponentInstance.class).get();
ComponentInstance tester = getContentWithName(eo.getEntityReference().getEntity().getName()+"_Tester", configuration, ComponentInstance.class).get();
tester.setRole(ComponentInstanceRole.TESTER);
transformConnection(configuration, i, tester);
}
}
private void transformConnection(TestConfiguration configuration, ComponentInstance i, ComponentInstance ti) {
//TODO: more gates?
Optional<Connection> optionalConnection = getConnectionBetween(i, ti, configuration);
Connection c;
if (optionalConnection.isPresent()) {
c = optionalConnection.get();
} else {
c = (Connection) tdlFactory.eINSTANCE.create(tdlPackage.Literals.CONNECTION);
GateReference gr1 = (GateReference) tdlFactory.eINSTANCE.create(tdlPackage.Literals.GATE_REFERENCE);
gr1.setComponent(i);
gr1.setGate(i.getType().getGateInstance().get(0));
GateReference gr2 = (GateReference) tdlFactory.eINSTANCE.create(tdlPackage.Literals.GATE_REFERENCE);
gr2.setComponent(ti);
gr2.setGate(ti.getType().getGateInstance().get(0));
c.getEndPoint().add(gr1);
c.getEndPoint().add(gr2);
configuration.getConnection().add(c);
}
}
private Optional<Connection> getConnectionBetween(ComponentInstance i, ComponentInstance ti, TestConfiguration configuration) {
Optional<Connection> optionalConnection = getContentWithPredicate(
e ->
(e.getEndPoint().get(0).getComponent().equals(i) &&
e.getEndPoint().get(1).getComponent().equals(ti)) ||
(e.getEndPoint().get(1).getComponent().equals(i) &&
e.getEndPoint().get(0).getComponent().equals(ti))
//TODO: check gates too?
, configuration, Connection.class);
return optionalConnection;
}
private void transform(EntityReference entityReference) {
transform(entityReference, "");
}
private void transform(EntityReference entityReference, String suffix) {
// TODO Auto-generated method stub
String componentTypeName = entityReference.getEntity().getName()+"_Type"+suffix;
String gateTypeName = entityReference.getEntity().getName()+"_GateType";
//TODO: this is not necessarily type safe, return depends on assignment
//TODO: extract?
GateType gateType = getTypeFor(gateTypeName, tdlPackage.Literals.GATE_TYPE);
EventOccurrenceSpecification eo = (EventOccurrenceSpecification) entityReference.container();
Value a = eo.getEventArgument();
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
if (a instanceof LiteralValue) {
String name = getQualifiedName((LiteralValue)a);
StructuredDataType generatedType = getStructuredDataTypeFor(name);
gateType.getDataType().add(generatedType);
}
ComponentType componentType = getTypeFor(componentTypeName, tdlPackage.Literals.COMPONENT_TYPE);
//TODO: at least one gate
String gateName = "g";
Optional<GateInstance> optional = componentType.getGateInstance().stream()
.filter(e -> e.getName().equals(gateName))
.findFirst();
GateInstance generatedGate;
if (optional.isPresent()) {
generatedGate = (GateInstance) optional.get();
} else {
generatedGate = tdlFactory.eINSTANCE.createGateInstance();
generatedGate.setName(gateName);
generatedGate.setType(gateType);
componentType.getGateInstance().add(generatedGate);
}
}
private void transform(LiteralValue lv) {
System.out.println(" "+NodeModelUtils.findActualNodeFor(lv).getText());
String name = getQualifiedName(lv);
StructuredDataType generatedType = getStructuredDataTypeFor(name);
transformMembers(generatedType, lv.getContent());
}
private String getQualifiedName(LiteralValue lv) {
String name = lv.getName();
if (useQualifiers) {
List<String> bodies = lv.getComment().stream()
.map(e->e.getBody())
.filter(e->!e.equals("the") && !e.equals("a"))
.collect(Collectors.toList());
if (!bodies.isEmpty()) {
name = String.join("_", bodies)+"_"+name;
}
}
return name;
}
private void transformMembers(StructuredDataType generatedType, EList<Content> allContent) {
List<String> memberNames = generatedType.getMember().stream()
.map(e -> e.getName())
.collect(Collectors.toList());
//TODO: warn if members exist but have different types
//TODO: without filter, effectively union
List<Content> content = allContent.stream()
// .filter(e->!memberNames.contains(e.getName()))
.filter(e->!e.getName().equals("omit")) //TODO: why the filter?
.collect(Collectors.toList());
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
Member m;
if (memberNames.contains(c.getName())) {
m = generatedType.getMember().get(memberNames.indexOf(c.getName()));
} else {
m = tdlFactory.eINSTANCE.createMember();
m.setName(c.getName());
}
//TODO: check types
if (!c.getContent().isEmpty()) {
m.setDataType(transform(generatedType, c));
} else if (c.getValue() instanceof LiteralValue) {
if (((LiteralValue) c.getValue()).getName().equals("B")) {
m.setDataType(getSimpleDataTypeFor("BITSTRING"));
} else {
m.setDataType(stringType);;
}
//TODO: structured types as well?
} else if (c.getValue() instanceof DataReference) {
if (((DataReference) c.getValue()).getContent() instanceof DataInstanceUse) {
DataInstanceUse dataInstanceUse = (DataInstanceUse)((DataReference) c.getValue()).getContent();
// System.out.println(dataInstanceUse.getDataInstance().getName()+":"+dataInstanceUse.getDataInstance().getDataType());
//m.setDataType(getSimpleDataTypeFor("TODO_RESOLVE_TYPE_FOR_"+dataInstanceUse.getDataInstance().getName()));;
m.setDataType(dataInstanceUse.getDataInstance().getDataType());
} else {
m.setDataType(referencedType);;
}
} else {
//otherwise default to string
m.setDataType(stringType);;
}
generatedType.getMember().add(m);
}
}
private StructuredDataType transform(StructuredDataType containerType, Content c) {
// StructuredDataType generatedType = getStructuredDataTypeFor(c.container().getName()+"_"+c.getName());
StructuredDataType generatedType = getStructuredDataTypeFor(containerType.getName()+"_"+c.getName());
transformMembers(generatedType, c.getContent());
return generatedType;
}
@Override
public void translate(String filename) throws Exception {
Resource sr = TDLHelper.load(filename);
Resource tr = TDLHelper.create(filename+"_generated.tdltx");
Package p = (Package) sr.getContents().get(0);
setTargetResource(tr);
initTargetResource("generated_from_"+p.getName());
addImports(p);
transform(p);
TDLHelper.store(tr);
}