Skip to content

Commit 3cfd8ed

Browse files
committed
[2174] Add the support for frame edge
Bug: #2174 Signed-off-by: Guillaume Coutable <guillaume.coutable@obeo.fr>
1 parent 2af51de commit 3cfd8ed

18 files changed

Lines changed: 464 additions & 12 deletions

File tree

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ Both tools optionally allow selecting an existing `StateUsage` to exhibit.
9696
- https://github.com/eclipse-syson/syson/issues/1979[#1979] [diagrams] Add tools to create timeslices and snapshots, available on `OccurrenceUsage`, `ItemUsage`, and `PartUsage` graphical nodes.
9797
These tools leverage a selection dialog to either create a specific timeslice/snapshot graphical node or, if no selection is made, default to a timeslice/snapshot `OccurrenceUsage` graphical node.
9898
- https://github.com/eclipse-syson/syson/issues/2176[#2176] [metamodel] Implements `ownedConcern` and `referencedConcern` of `FramedConcernMembership`.
99+
- https://github.com/eclipse-syson/syson/issues/2174[#2174] [diagrams] Add a new edge tool creating a frame edge between a `RequirementUsage` or a `RequirementDefinition` graphical node, and a `ConcernUsage` graphical node.
99100

100101
== v2026.3.0
101102

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 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.assertj.core.api.InstanceOfAssertFactories.type;
17+
import static org.eclipse.sirius.components.diagrams.tests.DiagramEventPayloadConsumer.assertRefreshedDiagramThat;
18+
import static org.eclipse.sirius.components.diagrams.tests.assertions.DiagramInstanceOfAssertFactories.EDGE;
19+
import static org.eclipse.sirius.components.diagrams.tests.assertions.DiagramInstanceOfAssertFactories.EDGE_STYLE;
20+
21+
import java.time.Duration;
22+
import java.util.List;
23+
import java.util.UUID;
24+
import java.util.concurrent.atomic.AtomicReference;
25+
import java.util.function.Consumer;
26+
27+
import org.eclipse.emf.ecore.EClass;
28+
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramEventInput;
29+
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramRefreshedEventPayload;
30+
import org.eclipse.sirius.components.core.api.IObjectSearchService;
31+
import org.eclipse.sirius.components.diagrams.ArrowStyle;
32+
import org.eclipse.sirius.components.diagrams.Diagram;
33+
import org.eclipse.sirius.components.diagrams.Edge;
34+
import org.eclipse.sirius.components.diagrams.Label;
35+
import org.eclipse.sirius.components.diagrams.ViewModifier;
36+
import org.eclipse.sirius.components.view.emf.diagram.IDiagramIdProvider;
37+
import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState;
38+
import org.eclipse.syson.AbstractIntegrationTests;
39+
import org.eclipse.syson.GivenSysONServer;
40+
import org.eclipse.syson.application.controller.editingcontext.checkers.SemanticCheckerService;
41+
import org.eclipse.syson.application.controllers.diagrams.testers.EdgeCreationTester;
42+
import org.eclipse.syson.application.data.GeneralViewWithTopNodesTestProjectData;
43+
import org.eclipse.syson.services.SemanticRunnableFactory;
44+
import org.eclipse.syson.services.diagrams.DiagramComparator;
45+
import org.eclipse.syson.services.diagrams.DiagramDescriptionIdProvider;
46+
import org.eclipse.syson.services.diagrams.api.IGivenDiagramDescription;
47+
import org.eclipse.syson.services.diagrams.api.IGivenDiagramSubscription;
48+
import org.eclipse.syson.standard.diagrams.view.SDVDescriptionNameGenerator;
49+
import org.eclipse.syson.sysml.FramedConcernMembership;
50+
import org.eclipse.syson.sysml.SysmlPackage;
51+
import org.eclipse.syson.sysml.helper.LabelConstants;
52+
import org.eclipse.syson.util.IDescriptionNameGenerator;
53+
import org.eclipse.syson.util.SysONRepresentationDescriptionIdentifiers;
54+
import org.junit.jupiter.api.BeforeEach;
55+
import org.junit.jupiter.api.Test;
56+
import org.springframework.beans.factory.annotation.Autowired;
57+
import org.springframework.boot.test.context.SpringBootTest;
58+
import org.springframework.transaction.annotation.Transactional;
59+
60+
import reactor.core.publisher.Flux;
61+
import reactor.test.StepVerifier;
62+
63+
/**
64+
* {@link org.eclipse.syson.sysml.FramedConcernMembership} related test in General View.
65+
*
66+
* @author gcoutable
67+
*/
68+
@Transactional
69+
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
70+
@SuppressWarnings("checkstyle:MultipleStringLiterals")
71+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
72+
public class GVFramedConcernTests extends AbstractIntegrationTests {
73+
74+
@Autowired
75+
private IGivenInitialServerState givenInitialServerState;
76+
77+
@Autowired
78+
private IGivenDiagramSubscription givenDiagramSubscription;
79+
80+
@Autowired
81+
private IGivenDiagramDescription givenDiagramDescription;
82+
83+
@Autowired
84+
private IDiagramIdProvider diagramIdProvider;
85+
86+
@Autowired
87+
private DiagramComparator diagramComparator;
88+
89+
@Autowired
90+
private SemanticRunnableFactory semanticRunnableFactory;
91+
92+
@Autowired
93+
private IObjectSearchService objectSearchService;
94+
95+
@Autowired
96+
private EdgeCreationTester edgeCreationTester;
97+
98+
private final IDescriptionNameGenerator descriptionNameGenerator = new SDVDescriptionNameGenerator();
99+
100+
private SemanticCheckerService semanticCheckerService;
101+
102+
private Flux<DiagramRefreshedEventPayload> givenSubscriptionToDiagram() {
103+
var diagramEventInput = new DiagramEventInput(UUID.randomUUID(), GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID, GeneralViewWithTopNodesTestProjectData.GraphicalIds.DIAGRAM_ID);
104+
return this.givenDiagramSubscription.subscribe(diagramEventInput);
105+
}
106+
107+
@BeforeEach
108+
public void setUp() {
109+
this.givenInitialServerState.initialize();
110+
this.semanticCheckerService = new SemanticCheckerService(this.semanticRunnableFactory, this.objectSearchService, GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID,
111+
GeneralViewWithTopNodesTestProjectData.SemanticIds.PACKAGE_1_ID);
112+
}
113+
114+
@Test
115+
public void testCreateFramedConcernWithEdgeBetweenRequirementUsageAndConcernUsage() {
116+
this.createFramedConcernWithEdge(SysmlPackage.eINSTANCE.getRequirementUsage(), GeneralViewWithTopNodesTestProjectData.GraphicalIds.REQUIREMENT_USAGE_ID, "requirement");
117+
}
118+
119+
@Test
120+
public void testCreateFramedConcernWithEdgeBetweenRequirementDefinitionAndConcernUsage() {
121+
this.createFramedConcernWithEdge(SysmlPackage.eINSTANCE.getRequirementDefinition(), GeneralViewWithTopNodesTestProjectData.GraphicalIds.REQUIREMENT_DEFINITION_ID, "RequirementDefinition");
122+
}
123+
124+
private void createFramedConcernWithEdge(EClass parentEClass, String graphicalSourceNodeId, String parentLabel) {
125+
var flux = this.givenSubscriptionToDiagram();
126+
127+
var diagramDescription = this.givenDiagramDescription.getDiagramDescription(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID,
128+
SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID);
129+
var diagramDescriptionIdProvider = new DiagramDescriptionIdProvider(diagramDescription, this.diagramIdProvider);
130+
131+
var edgeCreationToolId = diagramDescriptionIdProvider.getEdgeCreationToolId(
132+
this.descriptionNameGenerator.getNodeName(parentEClass),
133+
"New framed Concern");
134+
135+
AtomicReference<Diagram> diagram = new AtomicReference<>();
136+
Consumer<Object> initialDiagramContentConsumer = assertRefreshedDiagramThat(diagram::set);
137+
138+
Runnable createEdgeRunnable = () -> this.edgeCreationTester.createEdgeUsingNodeId(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID,
139+
diagram,
140+
graphicalSourceNodeId,
141+
GeneralViewWithTopNodesTestProjectData.GraphicalIds.CONCERN_USAGE_ID,
142+
edgeCreationToolId);
143+
144+
Consumer<Object> diagramContentConsumerAfterNewEdge = assertRefreshedDiagramThat(newDiagram -> {
145+
var newEdges = this.diagramComparator.newEdges(diagram.get(), newDiagram);
146+
var newVisibleEdges = newEdges.stream().filter(edge -> edge.getState() != ViewModifier.Hidden).toList();
147+
148+
assertThat(newVisibleEdges).hasSize(1).first(EDGE)
149+
.hasSourceId(graphicalSourceNodeId)
150+
.hasTargetId(GeneralViewWithTopNodesTestProjectData.GraphicalIds.CONCERN_USAGE_ID)
151+
.extracting(Edge::getCenterLabel)
152+
.extracting(Label::text)
153+
.hasToString(LabelConstants.OPEN_QUOTE + LabelConstants.FRAME + LabelConstants.CLOSE_QUOTE);
154+
155+
assertThat(newVisibleEdges).hasSize(1).first(EDGE)
156+
.extracting(Edge::getStyle, EDGE_STYLE)
157+
.hasSourceArrow(ArrowStyle.None)
158+
.hasTargetArrow(ArrowStyle.InputArrow);
159+
});
160+
161+
Consumer<Object> additionalCheck = object -> {
162+
assertThat(object).isInstanceOf(List.class)
163+
.asInstanceOf(type(List.class))
164+
.satisfies(framedConcerns -> {
165+
assertThat((List<?>) framedConcerns).size().isEqualTo(1);
166+
assertThat(framedConcerns.getFirst())
167+
.isInstanceOf(FramedConcernMembership.class)
168+
.asInstanceOf(type(FramedConcernMembership.class))
169+
.satisfies(framedConcernMembership -> {
170+
var ownedConcern = framedConcernMembership.getOwnedConcern();
171+
var ownedSubsetting = ownedConcern.getOwnedSubsetting();
172+
assertThat(ownedSubsetting).isNotEmpty();
173+
assertThat(ownedSubsetting.getFirst().getSubsettedFeature()).isEqualTo(framedConcernMembership.getReferencedConcern());
174+
});
175+
});
176+
};
177+
178+
Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, SysmlPackage.eINSTANCE.getElement_OwnedRelationship(), SysmlPackage.eINSTANCE.getFramedConcernMembership(), additionalCheck));
179+
180+
StepVerifier.create(flux)
181+
.consumeNextWith(initialDiagramContentConsumer)
182+
.then(createEdgeRunnable)
183+
.consumeNextWith(diagramContentConsumerAfterNewEdge)
184+
.then(semanticCheck)
185+
.thenCancel()
186+
.verify(Duration.ofSeconds(10));
187+
}
188+
}

backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/testers/EdgeCreationTester.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class EdgeCreationTester {
4747
@Autowired
4848
private InvokeSingleClickOnTwoDiagramElementsToolMutationRunner invokeSingleClickOnTwoDiagramElementsToolMutationRunner;
4949

50+
@Deprecated
5051
public void createEdge(String projectId, AtomicReference<Diagram> diagram, String sourceNodeTargetObjectLabel, String targetNodeTargetObjectLabel, String toolId) {
5152
DiagramNavigator diagramNavigator = new DiagramNavigator(diagram.get());
5253
String sourceId = diagramNavigator.nodeWithTargetObjectLabel(sourceNodeTargetObjectLabel).getNode().getId();

backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/GeneralViewWithTopNodesTestProjectData.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,27 @@ public class GeneralViewWithTopNodesTestProjectData {
2828
*/
2929
public static class GraphicalIds {
3030

31+
public static final String ACTION_USAGE_ID = "61aaf64a-4fbc-356e-ba73-4bd47b386989";
32+
33+
public static final String ATTRIBUTE_USAGE_ID = "7b8e6835-c563-35cd-8991-e2f894fc2139";
34+
35+
public static final String CONCERN_USAGE_ID = "0999b8c3-d37c-3644-a1d6-b9777a499d11";
36+
3137
public static final String DIAGRAM_ID = "fa8c8a8d-2813-404c-876f-c04e8b297134";
3238

39+
public static final String ITEM_DEFINITION_ID = "df3542d9-6314-3da5-993c-a296f4042674";
40+
3341
public static final String PART_USAGE_ID = "4c4fe0d5-4974-377e-9113-9ab022c75f8c";
3442

3543
public static final String PART_DEFINITION_ID = "fa617798-658e-3812-92f2-52e2fc39f851";
3644

3745
public static final String PART_DEFINITION_TEXTUAL_REP_ID = "3a992e49-95fa-384a-bb54-47284825bf17";
3846

39-
public static final String ACTION_USAGE_ID = "61aaf64a-4fbc-356e-ba73-4bd47b386989";
40-
41-
public static final String STATE_USAGE_ID = "1541c013-2cc7-3dd7-a39f-6e33d07b411e";
42-
43-
public static final String ATTRIBUTE_USAGE_ID = "7b8e6835-c563-35cd-8991-e2f894fc2139";
47+
public static final String REQUIREMENT_USAGE_ID = "3eea9d01-7033-3f31-b7ef-561b5bc86d10";
4448

45-
public static final String ITEM_DEFINITION_ID = "df3542d9-6314-3da5-993c-a296f4042674";
49+
public static final String REQUIREMENT_DEFINITION_ID = "b83f2b54-1602-382d-beb1-c500e08a8684";
4650

47-
public static final String REQUIREMENT_USAGE_ID = "3eea9d01-7033-3f31-b7ef-561b5bc86d10";
51+
public static final String STATE_USAGE_ID = "1541c013-2cc7-3dd7-a39f-6e33d07b411e";
4852
}
4953

5054
/**

backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/helper/LabelConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public class LabelConstants {
4949

5050
public static final String EQUAL = SysMLv2Keywords.EQUALS;
5151

52+
public static final String FRAME = SysMLv2Keywords.FRAME;
53+
5254
public static final String GREATER_THAN = SysMLv2Keywords.GREATER_THAN;
5355

5456
public static final String IN = SysMLv2Keywords.IN;

backend/services/syson-model-services/src/main/java/org/eclipse/syson/model/services/ModelMutationElementService.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,19 @@
1818
import org.eclipse.emf.ecore.EObject;
1919
import org.eclipse.emf.ecore.util.EcoreUtil;
2020
import org.eclipse.sirius.components.emf.utils.SiriusEMFCopier;
21+
import org.eclipse.syson.sysml.ConcernUsage;
2122
import org.eclipse.syson.sysml.Definition;
2223
import org.eclipse.syson.sysml.Element;
2324
import org.eclipse.syson.sysml.FeatureTyping;
25+
import org.eclipse.syson.sysml.FramedConcernMembership;
2426
import org.eclipse.syson.sysml.Namespace;
2527
import org.eclipse.syson.sysml.PartUsage;
2628
import org.eclipse.syson.sysml.Relationship;
29+
import org.eclipse.syson.sysml.RequirementDefinition;
2730
import org.eclipse.syson.sysml.RequirementUsage;
2831
import org.eclipse.syson.sysml.SatisfyRequirementUsage;
2932
import org.eclipse.syson.sysml.SysmlFactory;
33+
import org.eclipse.syson.sysml.Type;
3034
import org.eclipse.syson.sysml.ViewDefinition;
3135
import org.eclipse.syson.sysml.ViewUsage;
3236
import org.eclipse.syson.sysml.helper.EMFUtils;
@@ -199,6 +203,26 @@ public SatisfyRequirementUsage createSatisfy(Element element, RequirementUsage e
199203
return newSatisfyRequirementUsage;
200204
}
201205

206+
public FramedConcernMembership createFramedConcern(Type type, ConcernUsage concernUsage) {
207+
if (type instanceof RequirementDefinition || type instanceof RequirementUsage) {
208+
var newFramedConcernMembership = SysmlFactory.eINSTANCE.createFramedConcernMembership();
209+
type.getOwnedRelationship().add(newFramedConcernMembership);
210+
211+
var newConcernUsage = SysmlFactory.eINSTANCE.createConcernUsage();
212+
newFramedConcernMembership.getOwnedRelatedElement().add(newConcernUsage);
213+
214+
var newReferenceSubsetting = SysmlFactory.eINSTANCE.createReferenceSubsetting();
215+
newConcernUsage.getOwnedRelationship().add(newReferenceSubsetting);
216+
newReferenceSubsetting.setReferencedFeature(concernUsage);
217+
218+
this.metamodelMutationElementService.initialize(newFramedConcernMembership);
219+
this.metamodelMutationElementService.initialize(newConcernUsage);
220+
this.metamodelMutationElementService.initialize(newReferenceSubsetting);
221+
return newFramedConcernMembership;
222+
}
223+
return null;
224+
}
225+
202226
/**
203227
* Creates a {@link SatisfyRequirementUsage SatisfyRequirement} on {@code parentElement}.
204228
* <p>

backend/services/syson-model-services/src/main/java/org/eclipse/syson/model/services/aql/ModelMutationAQLService.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717
import org.eclipse.emf.ecore.EClass;
1818
import org.eclipse.emf.ecore.EObject;
1919
import org.eclipse.syson.model.services.ModelMutationElementService;
20+
import org.eclipse.syson.sysml.ConcernUsage;
2021
import org.eclipse.syson.sysml.Documentation;
2122
import org.eclipse.syson.sysml.Element;
2223
import org.eclipse.syson.sysml.Membership;
2324
import org.eclipse.syson.sysml.OccurrenceUsage;
2425
import org.eclipse.syson.sysml.PartUsage;
2526
import org.eclipse.syson.sysml.RequirementUsage;
27+
import org.eclipse.syson.sysml.Type;
2628
import org.eclipse.syson.sysml.ViewUsage;
2729
import org.eclipse.syson.sysml.metamodel.services.MetamodelMutationElementService;
2830

@@ -79,7 +81,7 @@ public Element createPartUsageAndFlowConnection(PartUsage self) {
7981
}
8082

8183
/**
82-
* {@link ModelMutationElementService#createPartUsageAndFlowConnection(PartUsage)}.
84+
* {@link ModelMutationElementService#createSatisfy(Element, RequirementUsage)}.
8385
*/
8486
public Element createSatisfy(Element element, RequirementUsage existingRequirement) {
8587
return this.modelMutationElementService.createSatisfy(element, existingRequirement);
@@ -105,4 +107,11 @@ public EObject createOccurrenceInOccurrence(OccurrenceUsage container, EClass eC
105107
public Element setAsView(ViewUsage viewUsage, String newViewDefinition) {
106108
return this.modelMutationElementService.setAsView(viewUsage, newViewDefinition);
107109
}
110+
111+
/**
112+
* {@link ModelMutationElementService#createFramedConcern(Type, ConcernUsage)}.
113+
*/
114+
public Element createFramedConcern(Type type, ConcernUsage concernUsage) {
115+
return this.modelMutationElementService.createFramedConcern(type, concernUsage);
116+
}
108117
}

backend/services/syson-model-services/src/main/java/org/eclipse/syson/model/services/aql/ModelQueryAQLService.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414

1515
import java.util.List;
1616

17+
import org.eclipse.syson.sysml.ConcernUsage;
1718
import org.eclipse.syson.sysml.Connector;
1819
import org.eclipse.syson.sysml.ConnectorAsUsage;
1920
import org.eclipse.syson.sysml.Element;
2021
import org.eclipse.syson.sysml.Feature;
22+
import org.eclipse.syson.sysml.FramedConcernMembership;
2123
import org.eclipse.syson.sysml.metamodel.services.MetamodelQueryElementService;
2224

2325
/**
@@ -68,4 +70,11 @@ public Feature getConnectorSource(Connector connector) {
6870
public List<Feature> getConnectorTarget(ConnectorAsUsage connector) {
6971
return this.metamodelQueryElementService.getConnectorTarget(connector);
7072
}
73+
74+
/**
75+
* {@link MetamodelQueryElementService#getFramedConcernTarget(FramedConcernMembership)}.
76+
*/
77+
public ConcernUsage getFramedConcernTarget(FramedConcernMembership framedConcernMembership) {
78+
return this.metamodelQueryElementService.getFramedConcernTarget(framedConcernMembership);
79+
}
7180
}

backend/services/syson-services/src/main/java/org/eclipse/syson/util/SysONEContentAdapter.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2024, 2025 Obeo.
2+
* Copyright (c) 2024, 2026 Obeo.
33
* This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v2.0
55
* which accompanies this distribution, and is available at
@@ -23,6 +23,7 @@
2323
import org.eclipse.emf.ecore.util.EContentAdapter;
2424
import org.eclipse.syson.sysml.Element;
2525
import org.eclipse.syson.sysml.FeatureValue;
26+
import org.eclipse.syson.sysml.FramedConcernMembership;
2627
import org.eclipse.syson.sysml.Membership;
2728

2829
/**
@@ -41,9 +42,8 @@ public Map<EClass, List<EObject>> getCache() {
4142
@Override
4243
protected void addAdapter(Notifier notifier) {
4344
super.addAdapter(notifier);
44-
// We need to keep FeatureValue since they may be displayed in representations
4545
// This adapter is used for semantic candidate expression
46-
if (notifier instanceof Element element && (!(notifier instanceof Membership) || notifier instanceof FeatureValue)) {
46+
if (notifier instanceof Element element && (!(notifier instanceof Membership) || this.shouldCacheMembership(notifier))) {
4747
EClass eClass = element.eClass();
4848
List<EObject> value;
4949
if (this.cache.containsKey(eClass)) {
@@ -74,4 +74,16 @@ protected void removeAdapter(Notifier notifier) {
7474
public boolean isAdapterForType(Object type) {
7575
return SysONEContentAdapter.class.equals(type);
7676
}
77+
78+
/**
79+
* Whether a membership should be cached.
80+
* <p>
81+
* We cache some memberships because they are displayed in a representation, either as a Node, or as an Edge.
82+
* </p>
83+
* @param notifier The notifier
84+
* @return whether the notifier is a membership that should be cached
85+
*/
86+
private boolean shouldCacheMembership(Notifier notifier) {
87+
return notifier instanceof FramedConcernMembership || notifier instanceof FeatureValue;
88+
}
7789
}

0 commit comments

Comments
 (0)