Skip to content

Commit 9083c3d

Browse files
committed
ST6RI-61 Fixed subset annotation in UML2Ecore bridge
1 parent 0fefaad commit 9083c3d

File tree

8 files changed

+1691
-1428
lines changed

8 files changed

+1691
-1428
lines changed

org.omg.sysml.uml.ecore.importer.tests/data/expected/SysML_from_tests_after_ST6RI-61.ecore

+488-465
Large diffs are not rendered by default.

org.omg.sysml.uml.ecore.importer.tests/data/input/SysML.uml

+947-946
Large diffs are not rendered by default.

org.omg.sysml.uml.ecore.importer.tests/src/org/omg/sysml/uml/ecore/importer/tests/UML2EcoreTest.java

+17
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,15 @@
33
import static org.junit.Assert.assertEquals;
44

55
import java.io.File;
6+
import java.io.IOException;
7+
import java.nio.file.Files;
8+
import java.nio.file.Path;
9+
import java.nio.file.Paths;
610
import java.util.HashMap;
11+
import java.util.List;
712
import java.util.Map;
13+
import java.util.stream.Collectors;
14+
import java.util.stream.Stream;
815

916
import org.apache.commons.io.FileUtils;
1017
import org.eclipse.emf.common.util.BasicMonitor;
@@ -77,9 +84,19 @@ public void convertUML2Ecore() throws Exception {
7784
options.put(XMLResource.OPTION_ENCODING, "UTF-8");
7885
ecoreResource.save(options);
7986

87+
formatOutput();
88+
8089
// compare with expected
8190
assertEquals(FileUtils.readFileToString(new File(EXPECTED), "utf-8"),
8291
FileUtils.readFileToString(new File(OUTPUT), "utf-8"));
8392
}
8493

94+
private void formatOutput() throws IOException {
95+
Path path = Paths.get(OUTPUT);
96+
Stream <String> lines = Files.lines(path);
97+
List <String> replaced = lines.map(line -> line.replaceAll(OUTPUT, "")).collect(Collectors.toList());
98+
Files.write(path, replaced);
99+
lines.close();
100+
}
101+
85102
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
package org.omg.sysml.uml.ecore.importer;
22

3+
import java.util.Collection;
4+
import java.util.Map;
5+
import java.util.Map.Entry;
6+
7+
import org.eclipse.emf.common.util.DiagnosticChain;
8+
import org.eclipse.emf.ecore.EAnnotation;
39
import org.eclipse.emf.ecore.EClass;
10+
import org.eclipse.emf.ecore.EModelElement;
11+
import org.eclipse.emf.ecore.EObject;
412
import org.eclipse.emf.ecore.EReference;
513
import org.eclipse.emf.ecore.EStructuralFeature;
614
import org.eclipse.emf.ecore.EcoreFactory;
715
import org.eclipse.uml2.uml.AggregationKind;
16+
import org.eclipse.uml2.uml.Element;
817
import org.eclipse.uml2.uml.Property;
918
import org.eclipse.uml2.uml.util.UMLUtil.UML2EcoreConverter;
1019

@@ -16,25 +25,66 @@
1625
*/
1726
public class CustomUML2EcoreConverter extends UML2EcoreConverter {
1827

28+
protected static final String ANNOTATION__SUBSETS = "subsets"; //$NON-NLS-1$
29+
1930
@Override
20-
public Object caseProperty(Property property) {
21-
Object res = super.caseProperty(property);
22-
23-
// We only change the conversion of composite properties
24-
if (AggregationKind.COMPOSITE_LITERAL.equals(property.getAggregation()) && res instanceof EReference) {
25-
EReference containmentReference = (EReference) res;
26-
27-
EReference normalReference = EcoreFactory.eINSTANCE.createEReference();
28-
normalReference.setName(property.getName());
29-
normalReference.setEType(containmentReference.getEType());
30-
normalReference.setLowerBound(containmentReference.getLowerBound());
31-
normalReference.setUpperBound(containmentReference.getUpperBound());
32-
33-
containmentReference.setName("comp_" + containmentReference.getName()); // added "comp" prefix to avoid EMF warning
34-
EClass container = (EClass) ((EStructuralFeature) res).eContainer();
35-
container.getEStructuralFeatures().add(normalReference);
36-
}
31+
public Collection<? extends EObject> convert(Collection<? extends EObject> eObjects, Map<String, String> options,
32+
DiagnosticChain diagnostics, Map<Object, Object> context) {
33+
Collection<? extends EObject> res = super.convert(eObjects, options, diagnostics, context);
34+
processReferences();
3735
return res;
3836
}
3937

38+
private void processReferences() {
39+
for (Entry<Element, EModelElement> entry : elementToEModelElementMap.entrySet()) {
40+
Element element = entry.getKey();
41+
EModelElement modelElement = entry.getValue();
42+
if (element instanceof Property && modelElement instanceof EReference
43+
&& ((EReference) modelElement).isMany()
44+
&& AggregationKind.COMPOSITE_LITERAL.equals(((Property) element).getAggregation())) {
45+
EAnnotation compSubsets = modelElement.getEAnnotation(ANNOTATION__SUBSETS);
46+
if (compSubsets != null) {
47+
EReference compRef = (EReference) modelElement;
48+
49+
// get the base reference from the initial annotation
50+
EReference baseRef = null;
51+
for (EObject ref : compSubsets.getReferences()) {
52+
if (ref instanceof EReference && ((EReference) ref).isContainment()) {
53+
baseRef = (EReference) ref;
54+
}
55+
}
56+
57+
if (baseRef != null) {
58+
// create a new EReference that will subset the base reference
59+
EReference normalRef = EcoreFactory.eINSTANCE.createEReference();
60+
normalRef.setName(compRef.getName());
61+
normalRef.setEType(compRef.getEType());
62+
normalRef.setLowerBound(compRef.getLowerBound());
63+
normalRef.setUpperBound(compRef.getUpperBound());
64+
65+
// change the reference name
66+
compRef.setName(compRef.getName() + "_comp");
67+
68+
// add the normal ref, now that its name is not in use anymore
69+
EClass container = (EClass) ((EStructuralFeature) compRef).eContainer();
70+
container.getEStructuralFeatures().add(normalRef);
71+
72+
// update the comp reference annotation
73+
compSubsets.getReferences().remove(baseRef);
74+
compSubsets.getReferences().add(normalRef);
75+
76+
// update the normal reference annotation
77+
EAnnotation normalSubsets = normalRef.getEAnnotation(ANNOTATION__SUBSETS);
78+
if (normalSubsets == null) {
79+
normalSubsets = EcoreFactory.eINSTANCE.createEAnnotation();
80+
normalSubsets.setSource(ANNOTATION__SUBSETS);
81+
normalRef.getEAnnotations().add(normalSubsets);
82+
}
83+
normalSubsets.getReferences().add(baseRef);
84+
}
85+
}
86+
}
87+
}
88+
}
89+
4090
}

org.omg.sysml.uml.ecore.importer/src/org/omg/sysml/uml/ecore/importer/CustomUMLImporter.java

+38
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
import java.util.Map;
2222
import java.util.StringTokenizer;
2323

24+
import org.eclipse.emf.codegen.ecore.genmodel.GenJDKLevel;
25+
import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
26+
import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
2427
import org.eclipse.emf.codegen.util.CodeGenUtil;
2528
import org.eclipse.emf.common.util.BasicDiagnostic;
2629
import org.eclipse.emf.common.util.Diagnostic;
@@ -43,6 +46,10 @@
4346

4447
public class CustomUMLImporter extends UMLImporter {
4548

49+
private static final String SYSML_URI = "http://www.omg.org/spec/SysML/2.0";
50+
private static final String BASE_PACKAGE = "org.omg.sysml.lang";
51+
private static final String TYPES_URI = "https://www.omg.org/spec/UML/20161101/PrimitiveTypes";
52+
4653
/*
4754
* MOSTLY FORKED FROM org.eclipse.uml2.uml.ecore.importer.UMLImporter except for
4855
* the UML2Ecore transformation
@@ -139,4 +146,35 @@ protected void processEcoreTaggedValues(EPackage ePackage, Element element, Map<
139146

140147
return diagnostic;
141148
}
149+
150+
@Override
151+
public void adjustEPackage(Monitor monitor, EPackage ePackage) {
152+
super.adjustEPackage(monitor, ePackage);
153+
if ("http://www.eclipse.org/uml2/5.0.0/Types".equals(ePackage.getNsURI())) {
154+
ePackage.setNsURI(TYPES_URI);
155+
ePackage.setNsPrefix("primitives");
156+
}
157+
ModelImporter.EPackageImportInfo ePackageInfo = getEPackageImportInfo(ePackage);
158+
if ("sysml.ecore".equals(ePackageInfo.getEcoreFileName())) {
159+
ePackageInfo.setEcoreFileName("SysML.ecore");
160+
}
161+
}
162+
163+
@Override
164+
protected void adjustGenModel(Monitor monitor) {
165+
super.adjustGenModel(monitor);
166+
GenModel current = getGenModel();
167+
168+
current.setModelDirectory("/" + getModelPluginID() + "/syntax-gen");
169+
170+
for (GenPackage genPackage : current.getGenPackages()) {
171+
if (TYPES_URI.equals(genPackage.getEcorePackage().getNsURI())) {
172+
genPackage.setBasePackage(BASE_PACKAGE);
173+
} else if (SYSML_URI.equals(genPackage.getEcorePackage().getNsURI())) {
174+
genPackage.setBasePackage(BASE_PACKAGE);
175+
genPackage.setPrefix("SysML");
176+
}
177+
}
178+
}
179+
142180
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2006, 2007 IBM Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v2.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v20.html
7+
*
8+
* Contributors:
9+
* IBM - initial API and implementation
10+
*
11+
* $Id: UMLImporterWizard.java,v 1.4 2007/05/30 20:11:19 khussey Exp $
12+
*/
13+
package org.omg.sysml.uml.ecore.importer.ui;
14+
15+
import org.eclipse.emf.importer.ModelImporter;
16+
import org.eclipse.swt.widgets.Composite;
17+
import org.eclipse.uml2.uml.ecore.importer.ui.UMLImporterDetailPage;
18+
import org.eclipse.uml2.uml.util.UMLUtil;
19+
20+
public class CustomUMLImporterDetailPage extends UMLImporterDetailPage {
21+
22+
public CustomUMLImporterDetailPage(ModelImporter modelImporter, String pageName) {
23+
super(modelImporter, pageName);
24+
}
25+
26+
@Override
27+
protected void addOptionControl(Composite parent, String text, String option, String[] choices,
28+
String initialChoice) {
29+
// default choices customization
30+
if (UMLUtil.UML2EcoreConverter.OPTION__REDEFINING_OPERATIONS.equals(option)) {
31+
super.addOptionControl(parent, text, option, choices, processChoiceLabel);
32+
} else if (UMLUtil.UML2EcoreConverter.OPTION__REDEFINING_PROPERTIES.equals(option)) {
33+
super.addOptionControl(parent, text, option, choices, processChoiceLabel);
34+
} else if (UMLUtil.UML2EcoreConverter.OPTION__SUBSETTING_PROPERTIES.equals(option)) {
35+
super.addOptionControl(parent, text, option, choices, processChoiceLabel);
36+
} else if (UMLUtil.UML2EcoreConverter.OPTION__UNION_PROPERTIES.equals(option)) {
37+
super.addOptionControl(parent, text, option, choices, processChoiceLabel);
38+
} else if (UMLUtil.UML2EcoreConverter.OPTION__INVARIANT_CONSTRAINTS.equals(option)) {
39+
super.addOptionControl(parent, text, option, choices, ignoreChoiceLabel);
40+
} else if (UMLUtil.UML2EcoreConverter.OPTION__OPERATION_BODIES.equals(option)) {
41+
super.addOptionControl(parent, text, option, choices, processChoiceLabel);
42+
} else if (UMLUtil.UML2EcoreConverter.OPTION__PROPERTY_DEFAULT_EXPRESSIONS.equals(option)) {
43+
super.addOptionControl(parent, text, option, choices, processChoiceLabel);
44+
} else if (UMLUtil.UML2EcoreConverter.OPTION__CAMEL_CASE_NAMES.equals(option)) {
45+
super.addOptionControl(parent, text, option, choices, processChoiceLabel);
46+
} else if (UMLUtil.UML2EcoreConverter.OPTION__OPPOSITE_ROLE_NAMES.equals(option)) {
47+
super.addOptionControl(parent, text, option, choices, processChoiceLabel);
48+
} else {
49+
super.addOptionControl(parent, text, option, choices, initialChoice);
50+
}
51+
}
52+
53+
}

org.omg.sysml.uml.ecore.importer/src/org/omg/sysml/uml/ecore/importer/ui/CustomUMLImporterWizard.java

+15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
package org.omg.sysml.uml.ecore.importer.ui;
1414

1515
import org.eclipse.emf.converter.ModelConverter;
16+
import org.eclipse.emf.importer.ui.contribution.base.ModelImporterPackagePage;
17+
import org.eclipse.uml2.uml.ecore.importer.ui.UMLImporterDetailPage;
1618
import org.eclipse.uml2.uml.ecore.importer.ui.UMLImporterWizard;
1719
import org.omg.sysml.uml.ecore.importer.CustomUMLImporter;
1820

@@ -22,4 +24,17 @@ public class CustomUMLImporterWizard extends UMLImporterWizard {
2224
protected ModelConverter createModelConverter() {
2325
return new CustomUMLImporter();
2426
}
27+
28+
@Override
29+
public void addPages() {
30+
UMLImporterDetailPage detailPage = new CustomUMLImporterDetailPage(getModelImporter(), "UMLImporterDetailPage"); //$NON-NLS-1$
31+
addPage(detailPage);
32+
33+
ModelImporterPackagePage packagePage = new ModelImporterPackagePage(getModelImporter(),
34+
"UMLImporterPackagePage") { //$NON-NLS-1$
35+
};
36+
37+
packagePage.setShowReferencedGenModels(true);
38+
addPage(packagePage);
39+
}
2540
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*****************************************************************************
2+
* SysML 2 Pilot Implementation
3+
* Copyright (c) 2019 Model Driven Solutions, Inc.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*
18+
* @license LGPL-3.0-or-later <http://spdx.org/licenses/LGPL-3.0-or-later>
19+
*
20+
* Contributors:
21+
* Ed Seidewitz
22+
*
23+
*****************************************************************************/
24+
25+
modeltype UML uses "http://www.eclipse.org/uml2/5.0.0/UML";
26+
27+
transformation PrepareMetamodel(inout uml: UML);
28+
29+
main() {
30+
var model := uml.rootObjects()![Model];
31+
model.packageImport := Set{};
32+
model.elementImport := Set{};
33+
var syntax := uml.objects()[Package]![name = "Abstract Syntax"];
34+
assert fatal (syntax <> null) with log ("Abstract Syntax not found.");
35+
syntax.map Namespace(model);
36+
model.packagedElement[Package]->destroy();
37+
model.name := "sysml";
38+
model.URI := "http://www.omg.org/spec/SysML/2.0";
39+
model.unapplyProfiles();
40+
}
41+
42+
helper Package::unapplyProfiles() {
43+
self.getAppliedProfiles()->forEach(profile) {
44+
self.unapplyProfile(profile);
45+
};
46+
// Remove stereotype applications
47+
uml.rootObjects()[obj | obj <> self]->forEach(obj) {
48+
uml.removeElement(obj)
49+
};
50+
}
51+
52+
mapping Package::Namespace(inout model: Model) {
53+
log("Package " + if self.namespace = null then "" else nameOf(self.namespace) + "::" endif + nameOf(self));
54+
self.ownedMember[Package]->map Namespace(model);
55+
if self <> model then {
56+
model.packagedElement += self.packagedElement;
57+
} endif
58+
}
59+
60+
query nameOf(element: NamedElement): String {
61+
return
62+
if element = null then "<null>"
63+
else if element.name = null or element.name = "" then "<empty>"
64+
else element.name
65+
endif endif
66+
}

0 commit comments

Comments
 (0)