Skip to content

Commit d9aba9f

Browse files
pcdavidAxelRICHARD
authored andcommitted
[2097] Handle expressions in SysON
Bug: #2097 Signed-off-by: Pierre-Charles David <pierre-charles.david@obeo.fr>
1 parent ec9b760 commit d9aba9f

63 files changed

Lines changed: 3651 additions & 177 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ Disabling the _Hide expression internals_ filter in the _Explorer_ view allows t
4040
- https://github.com/eclipse-syson/syson/issues/2235[#2235] [diagrams] Leverage the selection dialog to improve the graphical node tool creating a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes.
4141
- https://github.com/eclipse-syson/syson/issues/2242[#2242] [explorer] Add two options to the dialog creating a child element of `RequirementUsage` or `RequirementDefinition` tree items.
4242
One creates a `ConcernUsage` and another one creates `FramedConcernMembership`.
43+
- https://github.com/eclipse-syson/syson/issues/2097[#2097] [explorer] Add support for creating and editing exressions through their textual representation.
44+
This is currently supported on `Features` (e.g. `Attribute`), `Constraints` and `Transitions` (guard conditions) view new context menu actions (_Create expression_ and _Edit expression_) on the corresponding elements in the _Explorer_.
4345

4446
== v2026.5.0
4547

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.eclipse.emf.ecore.resource.Resource;
2626
import org.eclipse.emf.ecore.util.EcoreUtil;
2727
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
28-
import org.eclipse.syson.sysml.Element;
2928
import org.eclipse.emf.edit.provider.ComposedAdapterFactory.Descriptor;
3029
import org.eclipse.sirius.components.collaborative.forms.services.api.IPropertiesDescriptionRegistry;
3130
import org.eclipse.sirius.components.collaborative.forms.services.api.IPropertiesDescriptionRegistryConfigurer;
@@ -63,8 +62,9 @@
6362
import org.eclipse.syson.model.services.ModelMutationElementService;
6463
import org.eclipse.syson.model.services.aql.ModelMutationAQLService;
6564
import org.eclipse.syson.model.services.aql.ModelQueryAQLService;
66-
import org.eclipse.syson.services.UtilService;
65+
import org.eclipse.syson.sysml.Element;
6766
import org.eclipse.syson.sysml.SysmlPackage;
67+
import org.eclipse.syson.sysml.metamodel.services.MetamodelQueryElementService;
6868
import org.eclipse.syson.util.AQLConstants;
6969
import org.eclipse.syson.util.AQLUtils;
7070
import org.eclipse.syson.util.ServiceMethod;
@@ -119,10 +119,10 @@ public class SysMLv2PropertiesConfigurer implements IPropertiesDescriptionRegist
119119

120120
private final ILabelService labelService;
121121

122-
private final UtilService utilService;
123-
124122
private final IReadOnlyObjectPredicate readOnlyObjectPredicate;
125123

124+
private final MetamodelQueryElementService metamodelQueryElementService;
125+
126126
private final List<IDetailsViewHelpTextProvider> detailViewHelpTextProviders;
127127

128128
public SysMLv2PropertiesConfigurer(List<Descriptor> composedAdapterFactoryDescriptors, ViewFormDescriptionConverter converter, IFeedbackMessageService feedbackMessageService,
@@ -133,7 +133,7 @@ public SysMLv2PropertiesConfigurer(List<Descriptor> composedAdapterFactoryDescri
133133
this.labelService = Objects.requireNonNull(labelService);
134134
this.readOnlyObjectPredicate = Objects.requireNonNull(readOnlyObjectPredicate);
135135
this.detailViewHelpTextProviders = Objects.requireNonNull(detailViewHelpTextProviders);
136-
this.utilService = new UtilService();
136+
this.metamodelQueryElementService = new MetamodelQueryElementService();
137137
}
138138

139139
@Override
@@ -155,7 +155,8 @@ public void addPropertiesDescriptions(IPropertiesDescriptionRegistry registry) {
155155

156156
// Convert the View-based FormDescription and register the result into the system
157157
AQLInterpreter interpreter = new AQLInterpreter(List.of(),
158-
List.of(new DetailsViewService(this.composedAdapterFactoryDescriptors, this.feedbackMessageService, this.readOnlyObjectPredicate, this.detailViewHelpTextProviders), this.labelService, this.utilService,
158+
List.of(new DetailsViewService(this.composedAdapterFactoryDescriptors, this.feedbackMessageService, this.readOnlyObjectPredicate, this.metamodelQueryElementService,
159+
this.detailViewHelpTextProviders), this.labelService,
159160
new ModelMutationAQLService(new ModelMutationElementService()), new ModelQueryAQLService(), new FormMutationAQLService(), new FormQueryAQLService()),
160161
List.of(SysmlPackage.eINSTANCE));
161162
ViewConverterResult converterResult = this.converter.convert(viewFormDescription, List.of(), interpreter);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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.expressions.dto;
14+
15+
import java.util.UUID;
16+
17+
import org.eclipse.sirius.components.core.api.IInput;
18+
19+
/**
20+
* The input object for the {@code deleteExpression} mutation.
21+
*
22+
* @author pcdavid
23+
*/
24+
public record DeleteExpressionInput(UUID id, String editingContextId, String parentElementId) implements IInput {
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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.expressions.dto;
14+
15+
import java.util.UUID;
16+
17+
import org.eclipse.sirius.components.core.api.IInput;
18+
19+
/**
20+
* Input for the {@code expressionTextualRepresentation} query field on EditingContext.
21+
*
22+
* @author pcdavid
23+
*/
24+
public record ExpressionTextualRepresentationInput(UUID id, String editingContextId, String elementId) implements IInput {
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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.expressions.dto;
14+
15+
import java.util.Objects;
16+
import java.util.UUID;
17+
18+
import org.eclipse.sirius.components.core.api.IPayload;
19+
20+
/**
21+
* Payload for the {@code expressionTextualRepresentation} query field on EditingContext.
22+
*
23+
* @author pcdavid
24+
*/
25+
public record ExpressionTextualRepresentationPayload(UUID id, String textualRepresentation) implements IPayload {
26+
public ExpressionTextualRepresentationPayload {
27+
Objects.requireNonNull(id);
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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.expressions.graphql;
14+
15+
import java.util.Objects;
16+
import java.util.UUID;
17+
import java.util.concurrent.CompletableFuture;
18+
19+
import org.eclipse.sirius.components.annotations.spring.graphql.QueryDataFetcher;
20+
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;
21+
import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher;
22+
import org.eclipse.syson.application.expressions.dto.ExpressionTextualRepresentationInput;
23+
import org.eclipse.syson.application.expressions.dto.ExpressionTextualRepresentationPayload;
24+
25+
import graphql.schema.DataFetchingEnvironment;
26+
27+
/**
28+
* Data fetcher for the field {@code EditingContext#expressionTextualRepresentation} to fetch the textual representation
29+
* of a SysMLv2 expression.
30+
*
31+
* @author pcdavid
32+
*/
33+
@QueryDataFetcher(type = "EditingContext", field = "expressionTextualRepresentation")
34+
public class EditingContextExpressionTextualRepresentationDataFetcher implements IDataFetcherWithFieldCoordinates<CompletableFuture<String>> {
35+
36+
private static final String ELEMENT_ID_ARGUMENT = "elementId";
37+
38+
private final IEditingContextDispatcher editingContextDispatcher;
39+
40+
public EditingContextExpressionTextualRepresentationDataFetcher(IEditingContextDispatcher editingContextDispatcher) {
41+
this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher);
42+
}
43+
44+
@Override
45+
public CompletableFuture<String> get(DataFetchingEnvironment environment) throws Exception {
46+
String editingContextId = environment.getSource();
47+
String elementId = environment.getArgument(ELEMENT_ID_ARGUMENT);
48+
49+
ExpressionTextualRepresentationInput input = new ExpressionTextualRepresentationInput(UUID.randomUUID(), editingContextId, elementId);
50+
return this.editingContextDispatcher.dispatchQuery(input.editingContextId(), input)
51+
.filter(ExpressionTextualRepresentationPayload.class::isInstance)
52+
.map(ExpressionTextualRepresentationPayload.class::cast)
53+
.map(ExpressionTextualRepresentationPayload::textualRepresentation)
54+
.toFuture();
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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.expressions.graphql;
14+
15+
import java.util.Objects;
16+
import java.util.concurrent.CompletableFuture;
17+
18+
import org.eclipse.sirius.components.annotations.spring.graphql.MutationDataFetcher;
19+
import org.eclipse.sirius.components.core.api.IPayload;
20+
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;
21+
import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher;
22+
import org.eclipse.sirius.components.graphql.api.IExceptionWrapper;
23+
import org.eclipse.syson.application.expressions.dto.DeleteExpressionInput;
24+
25+
import graphql.schema.DataFetchingEnvironment;
26+
import tools.jackson.databind.ObjectMapper;
27+
28+
/**
29+
* The GraphQL data-fetcher for the {@code deleteExpression} mutation to delete the expression associated to a SysMLv2
30+
* element.
31+
*
32+
* @author pcdavid
33+
*/
34+
@MutationDataFetcher(type = "Mutation", field = "deleteExpression")
35+
public class MutationDeleteExpressionDataFetcher implements IDataFetcherWithFieldCoordinates<CompletableFuture<IPayload>> {
36+
37+
private static final String INPUT_ARGUMENT = "input";
38+
39+
private final ObjectMapper objectMapper;
40+
41+
private final IExceptionWrapper exceptionWrapper;
42+
43+
private final IEditingContextDispatcher editingContextDispatcher;
44+
45+
public MutationDeleteExpressionDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEditingContextDispatcher editingContextDispatcher) {
46+
this.objectMapper = Objects.requireNonNull(objectMapper);
47+
this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper);
48+
this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher);
49+
}
50+
51+
@Override
52+
public CompletableFuture<IPayload> get(DataFetchingEnvironment environment) throws Exception {
53+
Object argument = environment.getArgument(INPUT_ARGUMENT);
54+
var input = this.objectMapper.convertValue(argument, DeleteExpressionInput.class);
55+
return this.exceptionWrapper.wrapMono(() -> this.editingContextDispatcher.dispatchMutation(input.editingContextId(), input), input).toFuture();
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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.expressions.services;
14+
15+
import java.util.Objects;
16+
import java.util.Optional;
17+
18+
import org.eclipse.sirius.components.collaborative.api.ChangeDescription;
19+
import org.eclipse.sirius.components.collaborative.api.ChangeKind;
20+
import org.eclipse.sirius.components.collaborative.api.IEditingContextEventHandler;
21+
import org.eclipse.sirius.components.collaborative.messages.ICollaborativeMessageService;
22+
import org.eclipse.sirius.components.core.api.ErrorPayload;
23+
import org.eclipse.sirius.components.core.api.IEditingContext;
24+
import org.eclipse.sirius.components.core.api.IInput;
25+
import org.eclipse.sirius.components.core.api.IObjectSearchService;
26+
import org.eclipse.sirius.components.core.api.IPayload;
27+
import org.eclipse.sirius.components.core.api.SuccessPayload;
28+
import org.eclipse.syson.application.expressions.dto.DeleteExpressionInput;
29+
import org.eclipse.syson.services.DeleteService;
30+
import org.eclipse.syson.sysml.Element;
31+
import org.eclipse.syson.sysml.Expression;
32+
import org.eclipse.syson.sysml.metamodel.services.MetamodelQueryElementService;
33+
import org.springframework.stereotype.Service;
34+
35+
import reactor.core.publisher.Sinks;
36+
37+
/**
38+
* Event handler for the {@code deleteExpression} mutation.
39+
*
40+
* @author pcdavid
41+
*/
42+
@Service
43+
public class DeleteExpressionEventHandler implements IEditingContextEventHandler {
44+
45+
private final IObjectSearchService objectSearchService;
46+
47+
private final MetamodelQueryElementService metamodelQueryElementService;
48+
49+
private final ICollaborativeMessageService messageService;
50+
51+
private final DeleteService deleteService;
52+
53+
public DeleteExpressionEventHandler(IObjectSearchService objectSearchService, ICollaborativeMessageService messageService) {
54+
this.objectSearchService = Objects.requireNonNull(objectSearchService);
55+
this.metamodelQueryElementService = new MetamodelQueryElementService();
56+
this.messageService = Objects.requireNonNull(messageService);
57+
this.deleteService = new DeleteService();
58+
}
59+
60+
@Override
61+
public boolean canHandle(IEditingContext editingContext, IInput input) {
62+
return input instanceof DeleteExpressionInput;
63+
}
64+
65+
@Override
66+
public void handle(Sinks.One<IPayload> payloadSink, Sinks.Many<ChangeDescription> changeDescriptionSink, IEditingContext editingContext, IInput input) {
67+
IPayload payload;
68+
if (input instanceof DeleteExpressionInput deleteExpressionInput) {
69+
Optional<Expression> optionalExpression = this.objectSearchService.getObject(editingContext, deleteExpressionInput.parentElementId())
70+
.filter(Element.class::isInstance)
71+
.map(Element.class::cast)
72+
.flatMap(element -> this.metamodelQueryElementService.findSingleExpressionDefinition(element));
73+
if (optionalExpression.isPresent()) {
74+
this.deleteService.deleteFromModel(optionalExpression.get());
75+
var changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, editingContext.getId(), input);
76+
changeDescriptionSink.tryEmitNext(changeDescription);
77+
payload = new SuccessPayload(input.id());
78+
} else {
79+
payload = new ErrorPayload(input.id(), this.messageService.notFound());
80+
}
81+
} else {
82+
payload = new ErrorPayload(input.id(), this.messageService.invalidInput(DeleteExpressionInput.class.getName(), input.getClass().getName()));
83+
}
84+
payloadSink.tryEmitValue(payload);
85+
}
86+
}

0 commit comments

Comments
 (0)