Skip to content

Commit 5dc7858

Browse files
committed
[1314] Update ViewUsage#exposedElement when manipulating GeneralView
Bug: #1314 Signed-off-by: Axel RICHARD <axel.richard@obeo.fr>
1 parent d052aca commit 5dc7858

File tree

18 files changed

+590
-103
lines changed

18 files changed

+590
-103
lines changed

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ At the moment SysON only supports KerML and SysML, and does not support the defi
6969
- https://github.com/eclipse-syson/syson/issues/1251[#1251] [explorer] Create `ViewUsage` semantic element in addition to _Diagram_ on _New representation_ menu in _Explorer_ view.
7070
All existing SysON _DiagramDescriptions_ (i.g. _General View_, _Interconnection View_...) have been updated to reflect the fact that they now be associated to `ViewUsages`.
7171
- https://github.com/eclipse-syson/syson/issues/1310[#1310] [metamodel] Remove derived flag for `ViewUsage#exposedElement` feature.
72+
- https://github.com/eclipse-syson/syson/issues/1314[#1314] [general-view] Update `ViewUsage#exposedElement` when manipulating _General View_ diagram.
7273

7374
=== New features
7475

backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/CoreFeaturesSwitch.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.eclipse.syson.sysml.SysmlPackage;
4747
import org.eclipse.syson.sysml.TextualRepresentation;
4848
import org.eclipse.syson.sysml.Type;
49+
import org.eclipse.syson.sysml.ViewUsage;
4950
import org.eclipse.syson.sysml.util.SysmlSwitch;
5051

5152
/**
@@ -295,4 +296,12 @@ public List<EStructuralFeature> caseType(Type object) {
295296
features.add(SysmlPackage.eINSTANCE.getType_IsAbstract());
296297
return features;
297298
}
299+
300+
@Override
301+
public List<EStructuralFeature> caseViewUsage(ViewUsage object) {
302+
var features = new ArrayList<EStructuralFeature>();
303+
features.addAll(this.caseFeature(object));
304+
features.add(SysmlPackage.eINSTANCE.getViewUsage_ExposedElement());
305+
return features;
306+
}
298307
}

backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/DetailsViewService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
import org.eclipse.syson.sysml.SysmlPackage;
7171
import org.eclipse.syson.sysml.TransitionUsage;
7272
import org.eclipse.syson.sysml.Type;
73+
import org.eclipse.syson.sysml.ViewUsage;
7374
import org.eclipse.syson.sysml.util.ElementUtil;
7475

7576
/**
@@ -201,6 +202,8 @@ public boolean isReadOnly(Element element, EStructuralFeature eStructuralFeature
201202
isReadOnly = isReadOnly || ((Type) element).getOwnedFeature().stream().anyMatch(TransitionUsage.class::isInstance);
202203
} else if (element instanceof FeatureMembership && SysmlPackage.eINSTANCE.getFeaturing_Feature().equals(eStructuralFeature)) {
203204
isReadOnly = true;
205+
} else if (element instanceof ViewUsage && SysmlPackage.eINSTANCE.getViewUsage_ExposedElement().equals(eStructuralFeature)) {
206+
isReadOnly = true;
204207
}
205208
}
206209
return isReadOnly;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Obeo.
3+
* 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+
* https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Obeo - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.syson.application.controllers.diagrams.general.view;
14+
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
import static org.junit.jupiter.api.Assertions.assertEquals;
17+
18+
import java.time.Duration;
19+
import java.util.Optional;
20+
import java.util.UUID;
21+
import java.util.concurrent.atomic.AtomicReference;
22+
23+
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramEventInput;
24+
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramRefreshedEventPayload;
25+
import org.eclipse.sirius.components.core.api.IObjectSearchService;
26+
import org.eclipse.sirius.components.diagrams.Diagram;
27+
import org.eclipse.sirius.components.graphql.tests.ExecuteEditingContextFunctionSuccessPayload;
28+
import org.eclipse.sirius.components.view.diagram.DiagramDescription;
29+
import org.eclipse.sirius.components.view.emf.diagram.IDiagramIdProvider;
30+
import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState;
31+
import org.eclipse.syson.AbstractIntegrationTests;
32+
import org.eclipse.syson.application.controllers.diagrams.testers.NodeCreationTester;
33+
import org.eclipse.syson.application.data.ViewUsageExposedElementsTestProjectData;
34+
import org.eclipse.syson.diagram.general.view.GVDescriptionNameGenerator;
35+
import org.eclipse.syson.services.SemanticRunnableFactory;
36+
import org.eclipse.syson.services.diagrams.DiagramDescriptionIdProvider;
37+
import org.eclipse.syson.services.diagrams.api.IGivenDiagramDescription;
38+
import org.eclipse.syson.services.diagrams.api.IGivenDiagramReference;
39+
import org.eclipse.syson.services.diagrams.api.IGivenDiagramSubscription;
40+
import org.eclipse.syson.sysml.Element;
41+
import org.eclipse.syson.sysml.PartUsage;
42+
import org.eclipse.syson.sysml.SysmlPackage;
43+
import org.eclipse.syson.sysml.ViewUsage;
44+
import org.eclipse.syson.util.IDescriptionNameGenerator;
45+
import org.eclipse.syson.util.SysONRepresentationDescriptionIdentifiers;
46+
import org.junit.jupiter.api.AfterEach;
47+
import org.junit.jupiter.api.BeforeEach;
48+
import org.junit.jupiter.api.DisplayName;
49+
import org.junit.jupiter.api.Test;
50+
import org.springframework.beans.factory.annotation.Autowired;
51+
import org.springframework.boot.test.context.SpringBootTest;
52+
import org.springframework.test.context.jdbc.Sql;
53+
import org.springframework.test.context.jdbc.SqlConfig;
54+
import org.springframework.transaction.annotation.Transactional;
55+
56+
import reactor.test.StepVerifier;
57+
import reactor.test.StepVerifier.Step;
58+
59+
/**
60+
* Tests the synchronization between the diagram nodes and the ViewUsage#exposedElements reference.
61+
*
62+
* @author arichard
63+
*/
64+
@Transactional
65+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
66+
public class GVViewUsageExposedElements extends AbstractIntegrationTests {
67+
68+
private final IDescriptionNameGenerator descriptionNameGenerator = new GVDescriptionNameGenerator();
69+
70+
@Autowired
71+
private IGivenInitialServerState givenInitialServerState;
72+
73+
@Autowired
74+
private IGivenDiagramReference givenDiagram;
75+
76+
@Autowired
77+
private IGivenDiagramDescription givenDiagramDescription;
78+
79+
@Autowired
80+
private IGivenDiagramSubscription givenDiagramSubscription;
81+
82+
@Autowired
83+
private IDiagramIdProvider diagramIdProvider;
84+
85+
@Autowired
86+
private NodeCreationTester nodeCreationTester;
87+
88+
@Autowired
89+
private SemanticRunnableFactory semanticRunnableFactory;
90+
91+
@Autowired
92+
private IObjectSearchService objectSearchService;
93+
94+
private Step<DiagramRefreshedEventPayload> verifier;
95+
96+
private AtomicReference<Diagram> diagram;
97+
98+
private DiagramDescription diagramDescription;
99+
100+
private DiagramDescriptionIdProvider diagramDescriptionIdProvider;
101+
102+
@BeforeEach
103+
public void setUp() {
104+
this.givenInitialServerState.initialize();
105+
var diagramEventInput = new DiagramEventInput(UUID.randomUUID(),
106+
ViewUsageExposedElementsTestProjectData.EDITING_CONTEXT_ID,
107+
ViewUsageExposedElementsTestProjectData.GraphicalIds.DIAGRAM_ID);
108+
var flux = this.givenDiagramSubscription.subscribe(diagramEventInput);
109+
this.verifier = StepVerifier.create(flux);
110+
this.diagram = this.givenDiagram.getDiagram(this.verifier);
111+
this.diagramDescription = this.givenDiagramDescription.getDiagramDescription(ViewUsageExposedElementsTestProjectData.EDITING_CONTEXT_ID,
112+
SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID);
113+
this.diagramDescriptionIdProvider = new DiagramDescriptionIdProvider(this.diagramDescription, this.diagramIdProvider);
114+
}
115+
116+
@AfterEach
117+
public void tearDown() {
118+
if (this.verifier != null) {
119+
this.verifier.thenCancel()
120+
.verify(Duration.ofSeconds(10));
121+
}
122+
}
123+
124+
@DisplayName("GIVEN a GV diagram on a ViewUsage, WHEN New Part tool is executed, THEN a the ViewUsage#exposedElements is updated with the new Part")
125+
@Sql(scripts = { ViewUsageExposedElementsTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
126+
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
127+
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
128+
@Test
129+
public void newPartToolShouldUpdateExposedElements() {
130+
String creationToolId = this.diagramDescriptionIdProvider.getDiagramCreationToolId(this.descriptionNameGenerator.getCreationToolName(SysmlPackage.eINSTANCE.getPartUsage()));
131+
assertThat(creationToolId).as("The tool 'New Part' should exist on the diagram").isNotNull();
132+
this.verifier.then(() -> this.nodeCreationTester.createNodeOnDiagram(ViewUsageExposedElementsTestProjectData.EDITING_CONTEXT_ID,
133+
this.diagram,
134+
creationToolId));
135+
136+
this.verifier.consumeNextWith(payload -> Optional.of(payload));
137+
138+
Runnable semanticChecker = this.semanticRunnableFactory.createRunnable(ViewUsageExposedElementsTestProjectData.EDITING_CONTEXT_ID,
139+
(editingContext, executeEditingContextFunctionInput) -> {
140+
Object viewUsageObject = this.objectSearchService.getObject(editingContext, ViewUsageExposedElementsTestProjectData.SemanticIds.VIEW_USAGE_GV_ID).orElse(null);
141+
assertThat(viewUsageObject).isInstanceOf(ViewUsage.class);
142+
ViewUsage viewUsage = (ViewUsage) viewUsageObject;
143+
144+
assertEquals(1, viewUsage.getExposedElement().size());
145+
assertThat(viewUsage.getExposedElement().get(0)).isInstanceOf(PartUsage.class);
146+
assertThat(viewUsage.getExposedElement().get(0)).extracting(Element::getDeclaredName).isEqualTo("part2");
147+
148+
return new ExecuteEditingContextFunctionSuccessPayload(executeEditingContextFunctionInput.id(), true);
149+
});
150+
151+
this.verifier.then(semanticChecker);
152+
}
153+
154+
@DisplayName("GIVEN a GV diagram on a ViewUsage, WHEN Add existing element(s) tool is executed, THEN a the ViewUsage#exposedElements is updated with partA")
155+
@Sql(scripts = { ViewUsageExposedElementsTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
156+
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
157+
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
158+
@Test
159+
public void addExistingElementsToolShouldUpdateExposedElements() {
160+
String creationToolId = this.diagramDescriptionIdProvider.getDiagramCreationToolId("Add existing elements");
161+
assertThat(creationToolId).as("The tool 'Add existing elements' should exist on the diagram").isNotNull();
162+
this.verifier.then(() -> this.nodeCreationTester.createNodeOnDiagram(ViewUsageExposedElementsTestProjectData.EDITING_CONTEXT_ID,
163+
this.diagram,
164+
creationToolId));
165+
166+
this.verifier.consumeNextWith(payload -> Optional.of(payload));
167+
168+
Runnable semanticChecker = this.semanticRunnableFactory.createRunnable(ViewUsageExposedElementsTestProjectData.EDITING_CONTEXT_ID,
169+
(editingContext, executeEditingContextFunctionInput) -> {
170+
Object viewUsageObject = this.objectSearchService.getObject(editingContext, ViewUsageExposedElementsTestProjectData.SemanticIds.VIEW_USAGE_GV_ID).orElse(null);
171+
assertThat(viewUsageObject).isInstanceOf(ViewUsage.class);
172+
ViewUsage viewUsage = (ViewUsage) viewUsageObject;
173+
174+
assertEquals(1, viewUsage.getExposedElement().size());
175+
assertThat(viewUsage.getExposedElement().get(0)).isInstanceOf(PartUsage.class);
176+
assertThat(viewUsage.getExposedElement().get(0)).extracting(Element::getElementId).isEqualTo(ViewUsageExposedElementsTestProjectData.SemanticIds.PART_A_ID);
177+
178+
return new ExecuteEditingContextFunctionSuccessPayload(executeEditingContextFunctionInput.id(), true);
179+
});
180+
181+
this.verifier.then(semanticChecker);
182+
}
183+
184+
@DisplayName("GIVEN a GV diagram on a ViewUsage, WHEN Add existing element(s) (recursive) tool is executed, THEN a the ViewUsage#exposedElements is updated with partA and partB")
185+
@Sql(scripts = { ViewUsageExposedElementsTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
186+
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
187+
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
188+
@Test
189+
public void addExistingElementsRecursivelyToolShouldUpdateExposedElements() {
190+
String creationToolId = this.diagramDescriptionIdProvider.getDiagramCreationToolId("Add existing elements (recursive)");
191+
assertThat(creationToolId).as("The tool 'Add existing elements (recursive)' should exist on the diagram").isNotNull();
192+
this.verifier.then(() -> this.nodeCreationTester.createNodeOnDiagram(ViewUsageExposedElementsTestProjectData.EDITING_CONTEXT_ID,
193+
this.diagram,
194+
creationToolId));
195+
196+
this.verifier.consumeNextWith(payload -> Optional.of(payload));
197+
198+
Runnable semanticChecker = this.semanticRunnableFactory.createRunnable(ViewUsageExposedElementsTestProjectData.EDITING_CONTEXT_ID,
199+
(editingContext, executeEditingContextFunctionInput) -> {
200+
Object viewUsageObject = this.objectSearchService.getObject(editingContext, ViewUsageExposedElementsTestProjectData.SemanticIds.VIEW_USAGE_GV_ID).orElse(null);
201+
assertThat(viewUsageObject).isInstanceOf(ViewUsage.class);
202+
ViewUsage viewUsage = (ViewUsage) viewUsageObject;
203+
204+
assertEquals(2, viewUsage.getExposedElement().size());
205+
assertThat(viewUsage.getExposedElement().get(0)).isInstanceOf(PartUsage.class);
206+
assertThat(viewUsage.getExposedElement().get(0)).extracting(Element::getElementId).isEqualTo(ViewUsageExposedElementsTestProjectData.SemanticIds.PART_A_ID);
207+
assertThat(viewUsage.getExposedElement().get(1)).isInstanceOf(PartUsage.class);
208+
assertThat(viewUsage.getExposedElement().get(1)).extracting(Element::getElementId).isEqualTo(ViewUsageExposedElementsTestProjectData.SemanticIds.PART_B_ID);
209+
210+
return new ExecuteEditingContextFunctionSuccessPayload(executeEditingContextFunctionInput.id(), true);
211+
});
212+
213+
this.verifier.then(semanticChecker);
214+
}
215+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Obeo.
3+
* 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+
* https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Obeo - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.syson.application.data;
14+
15+
/**
16+
* Identifiers for the "ViewUsage-ExposedElements" project.
17+
*
18+
* @author arichard
19+
*/
20+
public class ViewUsageExposedElementsTestProjectData {
21+
22+
public static final String SCRIPT_PATH = "/scripts/database-content/ViewUsage-ExposedElements.sql";
23+
24+
public static final String PROJECT_NAME = "SysMLv2";
25+
26+
public static final String EDITING_CONTEXT_ID = "2ad408fb-f7b2-43cb-929a-e2b3d8cdf4af";
27+
28+
public static final String PROJECT_ID = "5ec64279-b533-461d-bdb4-2ac5de399710";
29+
30+
public static final String DOCUMENT_ID = "14a4121b-ec2e-41cd-99dd-c7612ba761bb";
31+
32+
/**
33+
* Ids of graphical elements.
34+
*/
35+
public static class GraphicalIds {
36+
37+
public static final String DIAGRAM_ID = "6bd4c626-403b-410e-a5d4-c0db131fb2dd";
38+
}
39+
40+
/**
41+
* Ids for the semantic elements.
42+
*/
43+
public static final class SemanticIds {
44+
45+
public static final String PACKAGE_1_ID = "f3d97864-09f0-4af7-95bd-44b1a3243fdb";
46+
47+
public static final String VIEW_USAGE_GV_ID = "b469efdb-1310-458e-a689-afd6e9f1702d";
48+
49+
public static final String PART_A_ID = "b2457be8-314c-4061-a307-54b79663790a";
50+
51+
public static final String PART_B_ID = "6209e9eb-446d-4b20-a90d-c211923b42f1";
52+
}
53+
54+
}

0 commit comments

Comments
 (0)