Skip to content

Commit

Permalink
[2618] Add pre and post-process around input processing
Browse files Browse the repository at this point in the history
Bug: #2618
Signed-off-by: Florian ROUËNÉ <florian.rouene@obeosoft.com>
  • Loading branch information
frouene authored and sbegaudeau committed Nov 27, 2023
1 parent e1223b4 commit 155ea2c
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
- [ADR-118] Use dynamic handles to connect edges between nodes
- [ADR-119] Share layout data between subscribers
- [ADR-120] Improve the arrange all action with reactflow
- [ADR-121] Add process before and after input handling

=== Breaking changes

Expand Down Expand Up @@ -139,6 +140,7 @@ The user can use 'shift+enter' to insert a line break.
- https://github.com/eclipse-sirius/sirius-web/issues/2255[#2255] [diagram] Add the possibility to specify a ratio on node to guarantee its aspect.
- https://github.com/eclipse-sirius/sirius-web/issues/2568[#2568] [trees] Allow developers to modify the content of the explorer view
- https://github.com/eclipse-sirius/sirius-web/issues/2570[#2570] [forms] Allow developers to modify the content of the details view
- https://github.com/eclipse-sirius/sirius-web/issues/2618[#2618] [core] Add an API to provide pre-process and post-process around input handling.

=== Improvements

Expand Down
39 changes: 39 additions & 0 deletions doc/adrs/121_add_process_before_and_after_input_handling.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
= ADR-121 - Add process before and after input handling

== Context

Today when you create a representation, you can only do so from the target element.
It is not possible, for example, to create a new intermediate semantic element to link it.

== Decision

Add the possibility to programmatically make some action before and after the input processing.
This pre-process should be able to change the input.
These actions should be able to make some semantic changes.

== Solution

* Add two new interfaces:

[source,java]
----
public interface IInputPreProcessor {
IInput preProcess(IEditingContext editingContext, IInput input, Many<ChangeDescription> changeDescriptionSink);
}
----

[source,java]
----
public interface IInputPostProcessor {
void postProcess(IEditingContext editingContext, IInput input, Many<ChangeDescription> changeDescriptionSink);
}
----

* In the `EditingContextEventProcessor#doHandle`, before invoking the _handleInput_ method, apply all the `IInputPreProcessor#preProcess` implementation on the input.
The input can be changed by the `IInputPreProcessor`, if several implementations exist, the order must be considered.

* The same way, just after the _handleInput_, apply all the `IInputPostProcessor#postProcess`.

== Status

Accepted
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.collaborative.api;

import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IInput;

import reactor.core.publisher.Sinks.Many;

/**
* API to provide actions after the input processing.
*
* @author frouene
*/
public interface IInputPostProcessor {

void postProcess(IEditingContext editingContext, IInput input, Many<ChangeDescription> changeDescriptionSink);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.collaborative.api;

import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IInput;

import reactor.core.publisher.Sinks.Many;

/**
* API to provide actions before the input processing.
*
* @author frouene
*/
public interface IInputPreProcessor {

IInput preProcess(IEditingContext editingContext, IInput input, Many<ChangeDescription> changeDescriptionSink);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.stream.Collectors;
Expand All @@ -33,6 +34,8 @@
import org.eclipse.sirius.components.collaborative.api.IDanglingRepresentationDeletionService;
import org.eclipse.sirius.components.collaborative.api.IEditingContextEventHandler;
import org.eclipse.sirius.components.collaborative.api.IEditingContextEventProcessor;
import org.eclipse.sirius.components.collaborative.api.IInputPostProcessor;
import org.eclipse.sirius.components.collaborative.api.IInputPreProcessor;
import org.eclipse.sirius.components.collaborative.api.IRepresentationConfiguration;
import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessor;
import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessorComposedFactory;
Expand Down Expand Up @@ -103,6 +106,10 @@ public class EditingContextEventProcessor implements IEditingContextEventProcess

private final Disposable changeDescriptionDisposable;

private final List<IInputPreProcessor> inputPreProcessors;

private final List<IInputPostProcessor> inputPostProcessors;

public EditingContextEventProcessor(EditingContextEventProcessorParameters parameters) {
this.messageService = parameters.messageService();
this.editingContext = parameters.editingContext();
Expand All @@ -112,6 +119,8 @@ public EditingContextEventProcessor(EditingContextEventProcessorParameters param
this.representationEventProcessorComposedFactory = parameters.representationEventProcessorComposedFactory();
this.danglingRepresentationDeletionService = parameters.danglingRepresentationDeletionService();
this.executorService = parameters.executorServiceProvider().getExecutorService(this.editingContext);
this.inputPreProcessors = parameters.inputPreProcessors();
this.inputPostProcessors = parameters.inputPostProcessors();
this.changeDescriptionDisposable = this.setupChangeDescriptionSinkConsumer();
}

Expand Down Expand Up @@ -233,27 +242,32 @@ public Mono<IPayload> handle(IInput input) {
* Finds the proper event handler to perform the task matching the given input event.
*
* @param payloadSink
* The sink to publish payload
* The sink to publish payload
* @param input
* The input event
* The input event
* @return The response computed by the event handler
*/
private void doHandle(One<IPayload> payloadSink, IInput input) {
this.logger.trace("Input received: {}", input);

if (input instanceof IRepresentationInput representationInput) {
AtomicReference<IInput> inputAfterPreProcessing = new AtomicReference<>(input);
this.inputPreProcessors.forEach(preProcessor -> inputAfterPreProcessing.set(preProcessor.preProcess(this.editingContext, inputAfterPreProcessing.get(), this.changeDescriptionSink)));

if (inputAfterPreProcessing.get() instanceof IRepresentationInput representationInput) {
this.handleRepresentationInput(payloadSink, representationInput);
} else {
this.handleInput(payloadSink, input);
this.handleInput(payloadSink, inputAfterPreProcessing.get());
}

this.inputPostProcessors.forEach(postProcessor -> postProcessor.postProcess(this.editingContext, inputAfterPreProcessing.get(), this.changeDescriptionSink));

}

/**
* Refresh all the representations except the one with the given representationId.
*
* @param changeDescription
* The description of change to consider in order to determine if the representation should be refreshed
* The description of change to consider in order to determine if the representation should be refreshed
*/
private void refreshOtherRepresentations(ChangeDescription changeDescription) {
// @formatter:off
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021 Obeo.
* Copyright (c) 2021, 2023 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand All @@ -19,6 +19,8 @@
import org.eclipse.sirius.components.collaborative.api.IEditingContextEventHandler;
import org.eclipse.sirius.components.collaborative.api.IEditingContextEventProcessor;
import org.eclipse.sirius.components.collaborative.api.IEditingContextEventProcessorFactory;
import org.eclipse.sirius.components.collaborative.api.IInputPostProcessor;
import org.eclipse.sirius.components.collaborative.api.IInputPreProcessor;
import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessorComposedFactory;
import org.eclipse.sirius.components.collaborative.editingcontext.api.IEditingContextEventProcessorExecutorServiceProvider;
import org.eclipse.sirius.components.collaborative.messages.ICollaborativeMessageService;
Expand Down Expand Up @@ -49,22 +51,25 @@ public class EditingContextEventProcessorFactory implements IEditingContextEvent

private final IEditingContextEventProcessorExecutorServiceProvider executorServiceProvider;

public EditingContextEventProcessorFactory(ICollaborativeMessageService messageService, IEditingContextPersistenceService editingContextPersistenceService,
ApplicationEventPublisher applicationEventPublisher, List<IEditingContextEventHandler> editingContextEventHandlers,
IRepresentationEventProcessorComposedFactory representationEventProcessorComposedFactory, IDanglingRepresentationDeletionService representationDeletionService,
IEditingContextEventProcessorExecutorServiceProvider executorServiceProvider) {
private final List<IInputPreProcessor> inputPreProcessors;

private final List<IInputPostProcessor> inputPostProcessors;

public EditingContextEventProcessorFactory(ICollaborativeMessageService messageService, ApplicationEventPublisher applicationEventPublisher,
IDanglingRepresentationDeletionService representationDeletionService, EditingContextEventProcessorFactoryParameters parameters) {
this.messageService = Objects.requireNonNull(messageService);
this.editingContextPersistenceService = Objects.requireNonNull(editingContextPersistenceService);
this.editingContextPersistenceService = parameters.getEditingContextPersistenceService();
this.applicationEventPublisher = Objects.requireNonNull(applicationEventPublisher);
this.editingContextEventHandlers = Objects.requireNonNull(editingContextEventHandlers);
this.representationEventProcessorComposedFactory = Objects.requireNonNull(representationEventProcessorComposedFactory);
this.editingContextEventHandlers = parameters.getEditingContextEventHandlers();
this.representationEventProcessorComposedFactory = parameters.getRepresentationEventProcessorComposedFactory();
this.representationDeletionService = Objects.requireNonNull(representationDeletionService);
this.executorServiceProvider = Objects.requireNonNull(executorServiceProvider);
this.executorServiceProvider = parameters.getExecutorServiceProvider();
this.inputPreProcessors = parameters.getInputPreProcessors();
this.inputPostProcessors = parameters.getInputPostProcessors();
}

@Override
public IEditingContextEventProcessor createEditingContextEventProcessor(IEditingContext editingContext) {
// @formatter:off
var parameters = EditingContextEventProcessorParameters.newEditingContextEventProcessorParameters()
.messageService(this.messageService)
.editingContext(editingContext)
Expand All @@ -74,8 +79,9 @@ public IEditingContextEventProcessor createEditingContextEventProcessor(IEditing
.representationEventProcessorComposedFactory(this.representationEventProcessorComposedFactory)
.danglingRepresentationDeletionService(this.representationDeletionService)
.executorServiceProvider(this.executorServiceProvider)
.inputPreProcessors(this.inputPreProcessors)
.inputPostProcessors(this.inputPostProcessors)
.build();
// @formatter:on
return new EditingContextEventProcessor(parameters);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.collaborative.editingcontext;

import java.util.List;
import java.util.Objects;

import org.eclipse.sirius.components.collaborative.api.IEditingContextEventHandler;
import org.eclipse.sirius.components.collaborative.api.IInputPostProcessor;
import org.eclipse.sirius.components.collaborative.api.IInputPreProcessor;
import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessorComposedFactory;
import org.eclipse.sirius.components.collaborative.editingcontext.api.IEditingContextEventProcessorExecutorServiceProvider;
import org.eclipse.sirius.components.core.api.IEditingContextPersistenceService;
import org.springframework.stereotype.Service;

/**
* Bundles the bean dependencies that {@link EditingContextEventProcessorFactory} needs into a single object for convenience.
*
* @author frouene
*/
@Service
public class EditingContextEventProcessorFactoryParameters {


private final IEditingContextPersistenceService editingContextPersistenceService;

private final List<IEditingContextEventHandler> editingContextEventHandlers;

private final IRepresentationEventProcessorComposedFactory representationEventProcessorComposedFactory;

private final IEditingContextEventProcessorExecutorServiceProvider executorServiceProvider;

private final List<IInputPreProcessor> inputPreProcessors;

private final List<IInputPostProcessor> inputPostProcessors;

public EditingContextEventProcessorFactoryParameters(IEditingContextPersistenceService editingContextPersistenceService, List<IEditingContextEventHandler> editingContextEventHandlers,
IRepresentationEventProcessorComposedFactory representationEventProcessorComposedFactory, IEditingContextEventProcessorExecutorServiceProvider executorServiceProvider,
List<IInputPreProcessor> inputPreProcessors, List<IInputPostProcessor> inputPostProcessors) {
this.editingContextPersistenceService = Objects.requireNonNull(editingContextPersistenceService);
this.editingContextEventHandlers = Objects.requireNonNull(editingContextEventHandlers);
this.representationEventProcessorComposedFactory = Objects.requireNonNull(representationEventProcessorComposedFactory);
this.executorServiceProvider = Objects.requireNonNull(executorServiceProvider);
this.inputPreProcessors = Objects.requireNonNull(inputPreProcessors);
this.inputPostProcessors = Objects.requireNonNull(inputPostProcessors);
}

public IEditingContextPersistenceService getEditingContextPersistenceService() {
return this.editingContextPersistenceService;
}

public List<IEditingContextEventHandler> getEditingContextEventHandlers() {
return this.editingContextEventHandlers;
}

public IRepresentationEventProcessorComposedFactory getRepresentationEventProcessorComposedFactory() {
return this.representationEventProcessorComposedFactory;
}

public IEditingContextEventProcessorExecutorServiceProvider getExecutorServiceProvider() {
return this.executorServiceProvider;
}

public List<IInputPreProcessor> getInputPreProcessors() {
return this.inputPreProcessors;
}

public List<IInputPostProcessor> getInputPostProcessors() {
return this.inputPostProcessors;
}
}

0 comments on commit 155ea2c

Please sign in to comment.