diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c59cbc9d..d28d96d0 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -43,7 +43,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -68,4 +68,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4866f577..675aad67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Changes - [graph] Updated the Graph model and add Layoutable interface [#175](https://github.com/eclipse-glsp/glsp-server/pull/175) - Contributed on behalf of STMicroelectronics +- [operation] Rework `OperationHandler` to provide an optional command instead of direct execution to allow more execution control [#187](https://github.com/eclipse-glsp/glsp-server/pull/187) ### Breaking Changes - [websocket] Update to Jetty Websocket 10 [#185](https://github.com/eclipse-glsp/glsp-server/pull/185) [#186](https://github.com/eclipse-glsp/glsp-server/pull/186) - Contributed on behalf of STMicroelectronics diff --git a/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/WorkflowDiagramModule.java b/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/WorkflowDiagramModule.java index 34e7ee51..fa04c703 100644 --- a/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/WorkflowDiagramModule.java +++ b/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/WorkflowDiagramModule.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -35,7 +35,7 @@ import org.eclipse.glsp.example.workflow.provider.PreviousNodeNavigationTargetProvider; import org.eclipse.glsp.example.workflow.provider.WorkflowCommandPaletteActionProvider; import org.eclipse.glsp.example.workflow.provider.WorkflowContextMenuItemProvider; -import org.eclipse.glsp.example.workflow.taskedit.ApplyTaskEditOperationHandler; +import org.eclipse.glsp.example.workflow.taskedit.ApplyTaskEditActionHandler; import org.eclipse.glsp.example.workflow.taskedit.EditTaskOperationHandler; import org.eclipse.glsp.example.workflow.taskedit.TaskEditContextActionProvider; import org.eclipse.glsp.example.workflow.taskedit.TaskEditValidator; @@ -104,7 +104,7 @@ protected void configureNavigationTargetProviders(final MultiBinding binding) { + protected void configureOperationHandlers(final MultiBinding> binding) { super.configureOperationHandlers(binding); binding.add(CreateAutomatedTaskHandler.class); binding.add(CreateManualTaskHandler.class); @@ -116,7 +116,6 @@ protected void configureOperationHandlers(final MultiBinding b binding.add(CreateWeightedEdgeHandler.class); binding.add(CreateCategoryHandler.class); binding.add(EditTaskOperationHandler.class); - binding.add(ApplyTaskEditOperationHandler.class); } @Override @@ -124,6 +123,7 @@ protected void configureActionHandlers(final MultiBinding binding super.configureActionHandlers(binding); binding.rebind(RequestContextActionsHandler.class, WorkflowRequestContextActionsHandler.class); binding.add(LogActionHandler.class); + binding.add(ApplyTaskEditActionHandler.class); } @Override diff --git a/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditOperation.java b/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditAction.java similarity index 82% rename from examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditOperation.java rename to examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditAction.java index b71994a6..1c8f2ae3 100644 --- a/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditOperation.java +++ b/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditAction.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,18 +15,18 @@ ********************************************************************************/ package org.eclipse.glsp.example.workflow.taskedit; -import org.eclipse.glsp.server.operations.Operation; +import org.eclipse.glsp.server.actions.Action; -public class ApplyTaskEditOperation extends Operation { +public class ApplyTaskEditAction extends Action { private String taskId; private String expression; - public ApplyTaskEditOperation() { + public ApplyTaskEditAction() { super("applyTaskEdit"); } - public ApplyTaskEditOperation(final String taskId, final String expression) { + public ApplyTaskEditAction(final String taskId, final String expression) { this(); this.taskId = taskId; this.expression = expression; diff --git a/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditOperationHandler.java b/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditActionHandler.java similarity index 62% rename from examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditOperationHandler.java rename to examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditActionHandler.java index 0486cc6c..94cc657a 100644 --- a/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditOperationHandler.java +++ b/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/ApplyTaskEditActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2021 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,33 +15,26 @@ ********************************************************************************/ package org.eclipse.glsp.example.workflow.taskedit; -import org.eclipse.glsp.server.actions.ActionDispatcher; -import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.operations.AbstractOperationHandler; -import org.eclipse.glsp.server.types.GLSPServerException; - -import com.google.inject.Inject; +import java.util.List; -public class ApplyTaskEditOperationHandler extends AbstractOperationHandler { - - @Inject - protected ActionDispatcher actionDispatcher; +import org.eclipse.glsp.server.actions.AbstractActionHandler; +import org.eclipse.glsp.server.actions.Action; +import org.eclipse.glsp.server.types.GLSPServerException; - @Inject - protected GModelState modelState; +public class ApplyTaskEditActionHandler extends AbstractActionHandler { @Override - protected void executeOperation(final ApplyTaskEditOperation operation) { - String text = operation.getExpression(); + protected List executeAction(final ApplyTaskEditAction actualAction) { + String text = actualAction.getExpression(); if (text.startsWith(TaskEditContextActionProvider.DURATION_PREFIX)) { String durationString = text.substring(TaskEditContextActionProvider.DURATION_PREFIX.length()); - actionDispatcher.dispatch(new EditTaskOperation(operation.getTaskId(), "duration", durationString)); + return listOf(new EditTaskOperation(actualAction.getTaskId(), "duration", durationString)); } else if (text.startsWith(TaskEditContextActionProvider.TYPE_PREFIX)) { String typeString = text.substring(TaskEditContextActionProvider.TYPE_PREFIX.length()); - actionDispatcher.dispatch(new EditTaskOperation(operation.getTaskId(), "taskType", typeString)); + return listOf(new EditTaskOperation(actualAction.getTaskId(), "taskType", typeString)); } else { throw new GLSPServerException( - "Cannot process 'ApplyTaskEditOperation' expression: " + operation.getExpression()); + "Cannot process 'ApplyTaskEditOperation' expression: " + actualAction.getExpression()); } } diff --git a/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/EditTaskOperationHandler.java b/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/EditTaskOperationHandler.java index 67f4d4be..c90020ee 100644 --- a/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/EditTaskOperationHandler.java +++ b/examples/org.eclipse.glsp.example.workflow/src/org/eclipse/glsp/example/workflow/taskedit/EditTaskOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2021 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,36 +15,31 @@ ********************************************************************************/ package org.eclipse.glsp.example.workflow.taskedit; +import java.util.Objects; import java.util.Optional; +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.example.workflow.wfgraph.TaskNode; -import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.operations.AbstractOperationHandler; -import org.eclipse.glsp.server.types.GLSPServerException; +import org.eclipse.glsp.server.operations.GModelOperationHandler; -import com.google.inject.Inject; - -public class EditTaskOperationHandler extends AbstractOperationHandler { - - @Inject - protected GModelState modelState; +public class EditTaskOperationHandler extends GModelOperationHandler { @Override - protected void executeOperation(final EditTaskOperation operation) { - Optional task = modelState.getIndex().findElementByClass(operation.getTaskId(), TaskNode.class); - if (task.isEmpty()) { - throw new RuntimeException("Cannot find task with id '" + operation.getTaskId() + "'"); - } + public Optional createCommand(final EditTaskOperation operation) { + TaskNode task = modelState.getIndex().findElementByClass(operation.getTaskId(), TaskNode.class) + .orElseThrow(() -> new RuntimeException("Cannot find task with id '" + operation.getTaskId() + "'")); switch (operation.getFeature()) { case "duration": - task.get().setDuration(Integer.parseInt(operation.getValue())); - break; + int duration = Integer.parseInt(operation.getValue()); + return Objects.equals(task.getDuration(), duration) + ? doNothing() + : commandOf(() -> task.setDuration(duration)); case "taskType": - task.get().setTaskType(operation.getValue()); - break; + return Objects.equals(task.getTaskType(), operation.getValue()) + ? doNothing() + : commandOf(() -> task.setTaskType(operation.getValue())); default: - throw new GLSPServerException("Cannot edit task at feature '" + operation.getFeature() + "'"); + return doNothing(); } } - } diff --git a/plugins/org.eclipse.glsp.graph/src/org/eclipse/glsp/graph/GModelIndex.java b/plugins/org.eclipse.glsp.graph/src/org/eclipse/glsp/graph/GModelIndex.java index f9767a6b..823b9da4 100644 --- a/plugins/org.eclipse.glsp.graph/src/org/eclipse/glsp/graph/GModelIndex.java +++ b/plugins/org.eclipse.glsp.graph/src/org/eclipse/glsp/graph/GModelIndex.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2021 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -78,6 +78,27 @@ static void remove(final GModelElement element) { */ Optional get(String elementId); + /** + * Returns an optional {@link GModelElement} by its elementId iff it also an instance of the given class. + * + * @param The type of the element to be found. + * @param elementId The id of the requested {@link GModelElement}. + * @param clazz The class of which the found element should be an instance. + * @return An optional with the element of type clazz or an empty optional. + * + * @see {@link #findElementByClass(String, Class)} to search the whole parent hierarchy. + */ + default Optional getByClass(final String elementId, final Class clazz) { + if (elementId == null) { + return Optional.empty(); + } + Optional element = get(elementId); + if (element.isPresent() && clazz.isInstance(element.get())) { + return Optional.of(clazz.cast(element.get())); + } + return Optional.empty(); + } + /** * Returns a set of {@link GModelElement} instances by a Collection of elementIds. * diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateEdgeOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateEdgeOperationHandler.java index 59bfd4c9..619e4d72 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateEdgeOperationHandler.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateEdgeOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 EclipseSource and others. + * Copyright (c) 2022-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -23,9 +23,15 @@ /** * A special {@link EMFOperationHandler} that is responsible for the handling of {@link CreateEdgeOperation}s. * It provides an EMF command to create the specific edge. + * + * @deprecated Use {@link EMFCreateOperationHandler} */ +@Deprecated public abstract class AbstractEMFCreateEdgeOperationHandler - extends AbstractEMFCreateOperationHandler implements CreateEdgeOperationHandler { + extends AbstractEMFCreateOperationHandler + implements CreateEdgeOperationHandler { + + protected List handledElementTypeIds; public AbstractEMFCreateEdgeOperationHandler(final String... elementTypeIds) { super(elementTypeIds); diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateNodeOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateNodeOperationHandler.java index 7e4196f2..b3cfe9fc 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateNodeOperationHandler.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateNodeOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 EclipseSource and others. + * Copyright (c) 2022-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -23,9 +23,13 @@ /** * A special {@link EMFOperationHandler} that is responsible for the handling of {@link CreateNodeOperation}s. * It provides an EMF command to create the specific node. + * + * @deprecated Use {@link EMFCreateNodeOperationHandler} */ +@Deprecated public abstract class AbstractEMFCreateNodeOperationHandler - extends AbstractEMFCreateOperationHandler implements CreateNodeOperationHandler { + extends AbstractEMFCreateOperationHandler + implements CreateNodeOperationHandler { public AbstractEMFCreateNodeOperationHandler(final String... elementTypeIds) { super(elementTypeIds); diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateOperationHandler.java index 98a48883..de931edc 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateOperationHandler.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFCreateOperationHandler.java @@ -17,11 +17,14 @@ import java.util.List; -import org.eclipse.glsp.server.operations.AbstractCreateOperationHandler; import org.eclipse.glsp.server.operations.CreateOperation; +/** + * @deprecated Use {@link EMFCreateOperationHandler} + */ +@Deprecated public abstract class AbstractEMFCreateOperationHandler - extends AbstractCreateOperationHandler implements EMFOperationHandler { + extends EMFCreateOperationHandler { public AbstractEMFCreateOperationHandler(final String... elementTypeIds) { super(elementTypeIds); @@ -31,9 +34,4 @@ public AbstractEMFCreateOperationHandler(final List handledElementTypeId super(handledElementTypeIds); } - @Override - protected void executeOperation(final O operation) { - EMFOperationHandler.super.execute(operation); - } - } diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFOperationHandler.java index 2712d936..e0cffda7 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFOperationHandler.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/AbstractEMFOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 EclipseSource and others. + * Copyright (c) 2022-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,15 +15,10 @@ ********************************************************************************/ package org.eclipse.glsp.server.emf; -import org.eclipse.glsp.server.operations.AbstractOperationHandler; import org.eclipse.glsp.server.operations.Operation; -public abstract class AbstractEMFOperationHandler extends AbstractOperationHandler - implements EMFOperationHandler { - - @Override - protected void executeOperation(final O operation) { - EMFOperationHandler.super.execute(operation); - } - -} +/** + * @deprecated Use {@link EMFOperationHandler} instead + */ +@Deprecated +public abstract class AbstractEMFOperationHandler extends EMFOperationHandler {} diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCompoundOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCompoundOperationHandler.java index 4c3debd4..66ff4815 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCompoundOperationHandler.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCompoundOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 EclipseSource and others. + * Copyright (c) 2022-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,36 +15,12 @@ ********************************************************************************/ package org.eclipse.glsp.server.emf; -import java.util.Optional; - -import org.eclipse.emf.common.command.Command; -import org.eclipse.emf.common.command.CompoundCommand; -import org.eclipse.glsp.server.operations.CompoundOperation; -import org.eclipse.glsp.server.operations.Operation; -import org.eclipse.glsp.server.operations.OperationHandlerRegistry; - -import com.google.inject.Inject; +import org.eclipse.glsp.server.operations.CompoundOperationHandler; /** * Creates a compound command to wrap multiple commands into one command that is executed on the command stack. + * + * @deprecated Use {@link CompoundOperationHandler} directly. */ -public class EMFCompoundOperationHandler extends AbstractEMFOperationHandler { - - @Inject - protected OperationHandlerRegistry operationHandlerRegistry; - - @Override - public Optional createCommand(final CompoundOperation operation) { - CompoundCommand compoundCommand = new CompoundCommand(); - operation.getOperationList() - .forEach(nestedOperation -> getNestedCommand(nestedOperation).ifPresent(compoundCommand::append)); - return compoundCommand.getCommandList().isEmpty() - ? Optional.empty() - : Optional.of(compoundCommand); - } - - protected Optional getNestedCommand(final Operation operation) { - return EMFOperationHandler.getCommand(operationHandlerRegistry, operation); - } - -} +@Deprecated +public class EMFCompoundOperationHandler extends CompoundOperationHandler {} diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCreateEdgeOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCreateEdgeOperationHandler.java new file mode 100644 index 00000000..b3cac24a --- /dev/null +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCreateEdgeOperationHandler.java @@ -0,0 +1,40 @@ +/******************************************************************************** + * Copyright (c) 2023 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +package org.eclipse.glsp.server.emf; + +import java.util.List; + +import org.eclipse.glsp.server.operations.CreateEdgeOperation; +import org.eclipse.glsp.server.operations.CreateEdgeOperationHandler; +import org.eclipse.glsp.server.operations.CreateNodeOperation; + +/** + * A special {@link EMFOperationHandler} that is responsible for the handling of {@link CreateNodeOperation}s. + * It provides an EMF command to create the specific node. + */ +public abstract class EMFCreateEdgeOperationHandler + extends EMFCreateOperationHandler + implements CreateEdgeOperationHandler { + + public EMFCreateEdgeOperationHandler(final String... elementTypeIds) { + super(elementTypeIds); + } + + public EMFCreateEdgeOperationHandler(final List handledElementTypeIds) { + super(handledElementTypeIds); + } + +} diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCreateNodeOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCreateNodeOperationHandler.java new file mode 100644 index 00000000..0fbc4d5b --- /dev/null +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCreateNodeOperationHandler.java @@ -0,0 +1,39 @@ +/******************************************************************************** + * Copyright (c) 2023 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +package org.eclipse.glsp.server.emf; + +import java.util.List; + +import org.eclipse.glsp.server.operations.CreateNodeOperation; +import org.eclipse.glsp.server.operations.CreateNodeOperationHandler; + +/** + * A special {@link EMFOperationHandler} that is responsible for the handling of {@link CreateNodeOperation}s. + * It provides an EMF command to create the specific node. + */ +public abstract class EMFCreateNodeOperationHandler + extends EMFCreateOperationHandler + implements CreateNodeOperationHandler { + + public EMFCreateNodeOperationHandler(final String... elementTypeIds) { + super(elementTypeIds); + } + + public EMFCreateNodeOperationHandler(final List handledElementTypeIds) { + super(handledElementTypeIds); + } + +} diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/BasicCreateOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCreateOperationHandler.java similarity index 53% rename from plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/BasicCreateOperationHandler.java rename to plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCreateOperationHandler.java index 3d0c4658..0c29f35e 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/BasicCreateOperationHandler.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFCreateOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2022 EclipseSource and others. + * Copyright (c) 2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,38 +13,37 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -package org.eclipse.glsp.server.operations; +package org.eclipse.glsp.server.emf; import java.util.List; -import org.eclipse.glsp.server.model.GModelState; +import org.eclipse.glsp.server.actions.ActionDispatcher; +import org.eclipse.glsp.server.operations.CreateOperation; +import org.eclipse.glsp.server.operations.CreateOperationHandler; import com.google.common.collect.Lists; import com.google.inject.Inject; -/** - * Deprecated, will be removed with version 1.0. - * Please use {@link AbstractCreateOperationHandler} instead and directly inject the {@link GModelState}. - */ -@Deprecated -public abstract class BasicCreateOperationHandler extends AbstractCreateOperationHandler { +public abstract class EMFCreateOperationHandler + extends EMFOperationHandler implements CreateOperationHandler { @Inject - protected GModelState modelState; + protected ActionDispatcher actionDispatcher; - public BasicCreateOperationHandler(final String... elementTypeIds) { + protected List handledElementTypeIds; + + public EMFCreateOperationHandler(final String... elementTypeIds) { this(Lists.newArrayList(elementTypeIds)); } - public BasicCreateOperationHandler(final List handledElementTypeIds) { + public EMFCreateOperationHandler(final List handledElementTypeIds) { this.handledElementTypeIds = handledElementTypeIds; } @Override - protected void executeOperation(final T operation) { - executeOperation(operation, modelState); - } - - protected abstract void executeOperation(T operation, GModelState modelState); + public List getHandledElementTypeIds() { return handledElementTypeIds; } + public void setHandledElementTypeIds(final List handledElementTypeIds) { + this.handledElementTypeIds = handledElementTypeIds; + } } diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFDiagramModule.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFDiagramModule.java index 4cd74ab2..59db988d 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFDiagramModule.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFDiagramModule.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 EclipseSource and others. + * Copyright (c) 2022-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,13 +15,8 @@ ********************************************************************************/ package org.eclipse.glsp.server.emf; -import org.eclipse.glsp.server.actions.ActionHandler; import org.eclipse.glsp.server.di.DiagramModule; -import org.eclipse.glsp.server.di.MultiBinding; import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.operations.CompoundOperationHandler; -import org.eclipse.glsp.server.operations.OperationActionHandler; -import org.eclipse.glsp.server.operations.OperationHandler; import com.google.inject.Singleton; @@ -71,15 +66,4 @@ protected void configureGModelState(final Class gmodelSta bind(EMFModelState.class).to((Class) gmodelStateClass); } - @Override - protected void configureActionHandlers(final MultiBinding binding) { - super.configureActionHandlers(binding); - binding.rebind(OperationActionHandler.class, EMFOperationActionHandler.class); - } - - @Override - protected void configureOperationHandlers(final MultiBinding binding) { - super.configureOperationHandlers(binding); - binding.rebind(CompoundOperationHandler.class, EMFCompoundOperationHandler.class); - } } diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFOperationActionHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFOperationActionHandler.java index 89902879..fbf6e124 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFOperationActionHandler.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFOperationActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 EclipseSource and others. + * Copyright (c) 2022-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,36 +15,13 @@ ********************************************************************************/ package org.eclipse.glsp.server.emf; -import java.util.List; -import java.util.Optional; - -import org.eclipse.emf.common.command.Command; -import org.eclipse.glsp.server.actions.Action; -import org.eclipse.glsp.server.actions.SetDirtyStateAction; -import org.eclipse.glsp.server.operations.Operation; import org.eclipse.glsp.server.operations.OperationActionHandler; /** * A special {@link OperationActionHandler} that executes provided EMF commands of {@link EMFOperationHandler} * on an EMF command stack via the {@link EMFModelState}. + * + * @deprecated Use {@link OperationActionHandler} directly */ -public class EMFOperationActionHandler extends OperationActionHandler { - - @Override - protected List executeOperation(final Operation operation) { - Optional command = EMFOperationHandler.getCommand(operationHandlerRegistry, operation); - if (command.isPresent()) { - exexcuteCommand(command.get()); - return submitModel(); - } - return super.executeOperation(operation); - } - - protected void exexcuteCommand(final Command cmd) { - modelState.execute(cmd); - } - - protected List submitModel() { - return modelSubmissionHandler.submitModel(SetDirtyStateAction.Reason.OPERATION); - } -} +@Deprecated +public class EMFOperationActionHandler extends OperationActionHandler {} diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFOperationHandler.java index d56d272e..f4d1994f 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFOperationHandler.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/EMFOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 EclipseSource and others. + * Copyright (c) 2022-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,67 +15,16 @@ ********************************************************************************/ package org.eclipse.glsp.server.emf; -import java.util.Optional; - -import org.eclipse.emf.common.command.Command; +import org.eclipse.glsp.server.operations.BasicOperationHandler; import org.eclipse.glsp.server.operations.Operation; import org.eclipse.glsp.server.operations.OperationHandler; -import org.eclipse.glsp.server.operations.OperationHandlerRegistry; + +import com.google.inject.Inject; /** * {@link OperationHandler} for EMF source models that creates commands to be executed on the command stack. */ -public interface EMFOperationHandler extends OperationHandler { - - @Override - Class getHandledOperationType(); - - /** - * @return the command to be applied to the EMF source model on the command stack for the given operation. - */ - default Optional getCommand(final Operation operation) { - if (handles(operation)) { - return createCommand(getHandledOperationType().cast(operation)); - } - return Optional.empty(); - } - - /** - * Creates a command that performs the operation in the EMF source model(s). - * - * @param operation The operation to process. - * @return The created command to be executed on the command stack. - */ - Optional createCommand(O operation); - - @Override - default void execute(final Operation operation) { - // do nothing, we use EMF commands to manipulate the model, see EMFOperationActionHandler - } - - /** - * Returns the EMF operation handler for the given operation from the given operation handler registry. - * - * @param operation type - * @param registry operation handler registry - * @param operation operation - * @return the matching EMF operation handler from the registry or empty if no such handler is found - */ - static Optional> getOperationHandler( - final OperationHandlerRegistry registry, final O operation) { - return registry.getOperationHandler(operation) - .filter(EMFOperationHandler.class::isInstance) - .map(EMFOperationHandler.class::cast); - } - - /** - * Returns the matching EMF command for the given operation. - * - * @param registry operation handler registry - * @param operation operation - * @return the matching EMF command for the given operation - */ - static Optional getCommand(final OperationHandlerRegistry registry, final Operation operation) { - return getOperationHandler(registry, operation).flatMap(handler -> handler.getCommand(operation)); - } +public abstract class EMFOperationHandler extends BasicOperationHandler { + @Inject + protected EMFModelState modelState; } diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/notation/EMFChangeBoundsOperationHandler.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/notation/EMFChangeBoundsOperationHandler.java index 8186ef90..dac04575 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/notation/EMFChangeBoundsOperationHandler.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/notation/EMFChangeBoundsOperationHandler.java @@ -24,7 +24,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.edit.command.SetCommand; import org.eclipse.emf.edit.domain.EditingDomain; -import org.eclipse.glsp.server.emf.AbstractEMFOperationHandler; +import org.eclipse.glsp.server.emf.EMFOperationHandler; import org.eclipse.glsp.server.emf.model.notation.NotationPackage; import org.eclipse.glsp.server.emf.model.notation.Shape; import org.eclipse.glsp.server.operations.ChangeBoundsOperation; @@ -35,7 +35,7 @@ /** * A custom change bounds operation handler that updates the notation model for the moved shape elements. */ -public class EMFChangeBoundsOperationHandler extends AbstractEMFOperationHandler { +public class EMFChangeBoundsOperationHandler extends EMFOperationHandler { @Inject protected EMFNotationModelState modelState; diff --git a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/notation/EMFNotationDiagramModule.java b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/notation/EMFNotationDiagramModule.java index 8ddb655c..d87fcc3b 100644 --- a/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/notation/EMFNotationDiagramModule.java +++ b/plugins/org.eclipse.glsp.server.emf/src/org/eclipse/glsp/server/emf/notation/EMFNotationDiagramModule.java @@ -54,7 +54,7 @@ protected Class bindSourceModelStorage() { } @Override - protected void configureOperationHandlers(final MultiBinding binding) { + protected void configureOperationHandlers(final MultiBinding> binding) { super.configureOperationHandlers(binding); binding.add(EMFChangeBoundsOperationHandler.class); } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/DiagramModule.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/DiagramModule.java index e424eeb3..c77ed662 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/DiagramModule.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/DiagramModule.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2021-2022 EclipseSource and others. + * Copyright (c) 2021-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -105,6 +105,7 @@ import org.eclipse.glsp.server.protocol.GLSPServer; import com.google.inject.Singleton; +import com.google.inject.TypeLiteral; import com.google.inject.multibindings.Multibinder; /** @@ -193,7 +194,7 @@ protected void configureBase() { configure(MultiBinding.create(Action.class).setAnnotationName(CLIENT_ACTIONS), this::configureClientActions); configure(MultiBinding.create(ActionHandler.class), this::configureActionHandlers); bind(ActionHandlerRegistry.class).to(bindActionHandlerRegistry()); - configure(MultiBinding.create(OperationHandler.class), this::configureOperationHandlers); + configure(MultiBinding.create(new TypeLiteral>() {}), this::configureOperationHandlers); bind(OperationHandlerRegistry.class).to(bindOperationHandlerRegistry()); // Navigation @@ -333,7 +334,7 @@ protected Class bindActionHandlerRegistry() { return DefaultActionHandlerRegistry.class; } - protected void configureOperationHandlers(final MultiBinding binding) { + protected void configureOperationHandlers(final MultiBinding> binding) { binding.add(CompoundOperationHandler.class); binding.add(LayoutOperationHandler.class); binding.add(CutOperationHandler.class); diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/AbstractGModelCreateEdgeOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/AbstractGModelCreateEdgeOperationHandler.java index d9e7eb8b..5004d7dc 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/AbstractGModelCreateEdgeOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/AbstractGModelCreateEdgeOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -29,20 +29,18 @@ import org.eclipse.glsp.server.operations.CreateEdgeOperation; import org.eclipse.glsp.server.operations.CreateEdgeOperationHandler; -import com.google.inject.Inject; - /** * Abstract base class for applying an {@link CreateEdgeOperation} directly to the GModel. + * + * @deprecated Use {@link GModelCreateEdgeOperationHandler} */ +@Deprecated public abstract class AbstractGModelCreateEdgeOperationHandler extends AbstractCreateOperationHandler - implements CreateEdgeOperationHandler { + implements CreateEdgeOperationHandler { protected final String label; - @Inject - protected GModelState modelState; - public AbstractGModelCreateEdgeOperationHandler(final String elementTypeId, final String label) { super(elementTypeId); this.label = label; diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/AbstractGModelCreateNodeOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/AbstractGModelCreateNodeOperationHandler.java index 6efbd602..7d9ae7d7 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/AbstractGModelCreateNodeOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/AbstractGModelCreateNodeOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -24,7 +24,6 @@ import org.eclipse.glsp.graph.GPoint; import org.eclipse.glsp.server.actions.ActionDispatcher; import org.eclipse.glsp.server.actions.SelectAction; -import org.eclipse.glsp.server.model.GModelState; import org.eclipse.glsp.server.operations.AbstractCreateOperationHandler; import org.eclipse.glsp.server.operations.CreateNodeOperation; import org.eclipse.glsp.server.operations.CreateNodeOperationHandler; @@ -34,13 +33,13 @@ /** * Abstract base class for applying an {@link CreateNodeOperation} directly to the GModel. + * + * @deprecated Use {@link GModelCreateNodeOperationHandler} */ +@Deprecated public abstract class AbstractGModelCreateNodeOperationHandler extends AbstractCreateOperationHandler - implements CreateNodeOperationHandler { - - @Inject - protected GModelState modelState; + implements CreateNodeOperationHandler { @Inject protected ActionDispatcher actionDispatcher; diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelApplyLabelEditOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelApplyLabelEditOperationHandler.java index 7ed277b3..8adde481 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelApplyLabelEditOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelApplyLabelEditOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,31 +15,29 @@ ********************************************************************************/ package org.eclipse.glsp.server.gmodel; +import java.util.Objects; import java.util.Optional; +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.graph.GLabel; -import org.eclipse.glsp.graph.GModelElement; import org.eclipse.glsp.server.features.directediting.ApplyLabelEditOperation; -import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.operations.AbstractOperationHandler; - -import com.google.inject.Inject; +import org.eclipse.glsp.server.operations.GModelOperationHandler; /** * Applies label changes directly to the GModel. */ -public class GModelApplyLabelEditOperationHandler extends AbstractOperationHandler { - - @Inject - protected GModelState modelState; +public class GModelApplyLabelEditOperationHandler extends GModelOperationHandler { @Override - public void executeOperation(final ApplyLabelEditOperation operation) { - Optional element = modelState.getIndex().get(operation.getLabelId()); - if (!element.isPresent() && !(element.get() instanceof GLabel)) { - throw new IllegalArgumentException("Element with provided ID cannot be found or is not a GLabel"); - } - GLabel sLabel = (GLabel) element.get(); - sLabel.setText(operation.getText()); + public Optional createCommand(final ApplyLabelEditOperation operation) { + GLabel label = findLabel(operation).orElseThrow( + () -> new IllegalArgumentException("Element with provided ID cannot be found or is not a GLabel")); + return Objects.equals(label.getText(), operation.getText()) + ? doNothing() + : commandOf(() -> label.setText(operation.getText())); + } + + protected Optional findLabel(final ApplyLabelEditOperation operation) { + return modelState.getIndex().getByClass(operation.getLabelId(), GLabel.class); } } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelChangeBoundsOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelChangeBoundsOperationHandler.java index 2de85da7..e10b4635 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelChangeBoundsOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelChangeBoundsOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -17,8 +17,11 @@ import static org.eclipse.glsp.server.types.GLSPServerException.getOrThrow; +import java.util.Optional; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.graph.GDimension; import org.eclipse.glsp.graph.GModelElement; import org.eclipse.glsp.graph.GModelIndex; @@ -27,25 +30,23 @@ import org.eclipse.glsp.graph.GPoint; import org.eclipse.glsp.graph.builder.impl.GLayoutOptions; import org.eclipse.glsp.graph.util.GraphUtil; -import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.operations.AbstractOperationHandler; import org.eclipse.glsp.server.operations.ChangeBoundsOperation; +import org.eclipse.glsp.server.operations.GModelOperationHandler; import org.eclipse.glsp.server.types.ElementAndBounds; -import com.google.inject.Inject; - /** * Applies {@link ChangeBoundsOperation} directly to the GModel. */ -public class GModelChangeBoundsOperationHandler extends AbstractOperationHandler { +public class GModelChangeBoundsOperationHandler extends GModelOperationHandler { private static Logger LOGGER = LogManager.getLogger(GModelChangeBoundsOperationHandler.class); - @Inject - protected GModelState modelState; - @Override - public void executeOperation(final ChangeBoundsOperation operation) { + public Optional createCommand(final ChangeBoundsOperation operation) { + return commandOf(() -> executeChangeBounds(operation)); + } + + protected void executeChangeBounds(final ChangeBoundsOperation operation) { for (ElementAndBounds element : operation.getNewBounds()) { changeElementBounds(element.getElementId(), element.getNewPosition(), element.getNewSize()); } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelChangeRoutingPointsHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelChangeRoutingPointsHandler.java index e6da02f1..e4743452 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelChangeRoutingPointsHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelChangeRoutingPointsHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,24 +15,25 @@ ********************************************************************************/ package org.eclipse.glsp.server.gmodel; +import java.util.Optional; + +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.graph.GModelIndex; -import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.operations.AbstractOperationHandler; import org.eclipse.glsp.server.operations.ChangeRoutingPointsOperation; +import org.eclipse.glsp.server.operations.GModelOperationHandler; import org.eclipse.glsp.server.utils.LayoutUtil; -import com.google.inject.Inject; - /** * Applies {@link ChangeRoutingPointsOperation} directly to the GModel. */ -public class GModelChangeRoutingPointsHandler extends AbstractOperationHandler { - - @Inject - protected GModelState modelState; +public class GModelChangeRoutingPointsHandler extends GModelOperationHandler { @Override - protected void executeOperation(final ChangeRoutingPointsOperation operation) { + public Optional createCommand(final ChangeRoutingPointsOperation operation) { + return commandOf(() -> executeChangeRoutingPoints(operation)); + } + + protected void executeChangeRoutingPoints(final ChangeRoutingPointsOperation operation) { if (operation.getNewRoutingPoints() == null) { throw new IllegalArgumentException("Incomplete change routingPoints action"); } @@ -40,4 +41,5 @@ protected void executeOperation(final ChangeRoutingPointsOperation operation) { GModelIndex index = modelState.getIndex(); operation.getNewRoutingPoints().forEach(routingPoints -> LayoutUtil.applyRoutingPoints(routingPoints, index)); } + } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelCreateEdgeOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelCreateEdgeOperationHandler.java new file mode 100644 index 00000000..d48acda2 --- /dev/null +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelCreateEdgeOperationHandler.java @@ -0,0 +1,79 @@ +/******************************************************************************** + * Copyright (c) 2023 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +package org.eclipse.glsp.server.gmodel; + +import static org.eclipse.glsp.server.utils.GModelUtil.IS_CONNECTABLE; + +import java.util.List; +import java.util.Optional; + +import org.eclipse.emf.common.command.Command; +import org.eclipse.glsp.graph.GEdge; +import org.eclipse.glsp.graph.GModelElement; +import org.eclipse.glsp.graph.GModelIndex; +import org.eclipse.glsp.graph.GModelRoot; +import org.eclipse.glsp.server.model.GModelState; +import org.eclipse.glsp.server.operations.CreateEdgeOperation; +import org.eclipse.glsp.server.operations.CreateEdgeOperationHandler; + +/** + * Abstract base class for applying an {@link CreateEdgeOperation} directly to the GModel. + */ +public abstract class GModelCreateEdgeOperationHandler + extends GModelCreateOperationHandler + implements CreateEdgeOperationHandler { + + public GModelCreateEdgeOperationHandler(final String... elementTypeIds) { + super(elementTypeIds); + } + + public GModelCreateEdgeOperationHandler(final List handledElementTypeIds) { + super(handledElementTypeIds); + } + + @Override + public Optional createCommand(final CreateEdgeOperation operation) { + return commandOf(() -> execute(operation)); + } + + public void executeCreation(final CreateEdgeOperation operation) { + if (operation.getSourceElementId() == null || operation.getTargetElementId() == null) { + throw new IllegalArgumentException("Incomplete create connection action"); + } + + GModelIndex index = modelState.getIndex(); + + Optional source = index.findElement(operation.getSourceElementId(), IS_CONNECTABLE); + Optional target = index.findElement(operation.getTargetElementId(), IS_CONNECTABLE); + if (!source.isPresent() || !target.isPresent()) { + throw new IllegalArgumentException("Invalid source or target for source ID " + operation.getSourceElementId() + + " and target ID " + operation.getTargetElementId()); + } + + Optional connection = createEdge(source.get(), target.get(), modelState); + if (!connection.isPresent()) { + throw new IllegalArgumentException( + String.format("Creation of connection failed for source: %s , target: %s", source.get().getId(), + target.get().getId())); + } + GModelRoot currentModel = modelState.getRoot(); + currentModel.getChildren().add(connection.get()); + } + + protected abstract Optional createEdge(GModelElement source, GModelElement target, + GModelState modelState); + +} diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelCreateNodeOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelCreateNodeOperationHandler.java new file mode 100644 index 00000000..43ee82f1 --- /dev/null +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelCreateNodeOperationHandler.java @@ -0,0 +1,94 @@ +/******************************************************************************** + * Copyright (c) 2023 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +package org.eclipse.glsp.server.gmodel; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.eclipse.emf.common.command.Command; +import org.eclipse.glsp.graph.GModelElement; +import org.eclipse.glsp.graph.GNode; +import org.eclipse.glsp.graph.GPoint; +import org.eclipse.glsp.server.actions.ActionDispatcher; +import org.eclipse.glsp.server.actions.SelectAction; +import org.eclipse.glsp.server.operations.CreateEdgeOperation; +import org.eclipse.glsp.server.operations.CreateNodeOperation; +import org.eclipse.glsp.server.operations.CreateNodeOperationHandler; + +import com.google.inject.Inject; + +/** + * Abstract base class for applying an {@link CreateEdgeOperation} directly to the GModel. + */ +public abstract class GModelCreateNodeOperationHandler + extends GModelCreateOperationHandler + implements CreateNodeOperationHandler { + + @Inject + protected ActionDispatcher actionDispatcher; + + public GModelCreateNodeOperationHandler(final String... elementTypeIds) { + super(elementTypeIds); + } + + public GModelCreateNodeOperationHandler(final List handledElementTypeIds) { + super(handledElementTypeIds); + } + + @Override + public Optional createCommand(final CreateNodeOperation operation) { + return commandOf(() -> execute(operation)); + } + + public void executeCreation(final CreateNodeOperation operation) { + GModelElement container = getContainer(operation).orElseGet(modelState::getRoot); + Optional absoluteLocation = getLocation(operation); + Optional relativeLocation = getRelativeLocation(operation, absoluteLocation, container); + GModelElement element = createNode(relativeLocation, operation.getArgs()); + container.getChildren().add(element); + actionDispatcher.dispatchAfterNextUpdate(new SelectAction(), new SelectAction(List.of(element.getId()))); + } + + /** + *

+ * Return the GModelElement that will contain the newly created node. It is usually + * the target element ({@link CreateNodeOperation#getContainerId()}), but could also + * be e.g. an intermediate compartment, or even a different Node. + *

+ * + * @param operation + * @return + * the GModelElement that will contain the newly created node. + */ + protected Optional getContainer(final CreateNodeOperation operation) { + return modelState.getIndex().get(operation.getContainerId()); + } + + /** + * Create and return the new Node at the specified (optional) location. The location + * is given in coordinates relative to the + * {@link AbstractGModelCreateNodeOperationHandler#getContainer(CreateNodeOperation)} + * container. + * + * @param relativeLocation + * @param args + * @return + * The created {@link GNode Node}. + */ + protected abstract GNode createNode(Optional relativeLocation, Map args); + +} diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelCreateOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelCreateOperationHandler.java new file mode 100644 index 00000000..740d3324 --- /dev/null +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelCreateOperationHandler.java @@ -0,0 +1,55 @@ +/******************************************************************************** + * Copyright (c) 2023 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +package org.eclipse.glsp.server.gmodel; + +import java.util.List; + +import org.eclipse.glsp.server.actions.ActionDispatcher; +import org.eclipse.glsp.server.operations.CreateEdgeOperation; +import org.eclipse.glsp.server.operations.CreateOperation; +import org.eclipse.glsp.server.operations.CreateOperationHandler; +import org.eclipse.glsp.server.operations.GModelOperationHandler; + +import com.google.common.collect.Lists; +import com.google.inject.Inject; + +/** + * Abstract base class for applying an {@link CreateEdgeOperation} directly to the GModel. + */ +public abstract class GModelCreateOperationHandler + extends GModelOperationHandler implements CreateOperationHandler { + + @Inject + protected ActionDispatcher actionDispatcher; + + protected List handledElementTypeIds; + + public GModelCreateOperationHandler(final String... elementTypeIds) { + this(Lists.newArrayList(elementTypeIds)); + } + + public GModelCreateOperationHandler(final List handledElementTypeIds) { + this.handledElementTypeIds = handledElementTypeIds; + } + + @Override + public List getHandledElementTypeIds() { return handledElementTypeIds; } + + public void setHandledElementTypeIds(final List handledElementTypeIds) { + this.handledElementTypeIds = handledElementTypeIds; + } + +} diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelDeleteOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelDeleteOperationHandler.java index 910a49e8..a270d484 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelDeleteOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelDeleteOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -24,34 +24,34 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.eclipse.emf.common.command.Command; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.glsp.graph.GEdge; import org.eclipse.glsp.graph.GModelElement; import org.eclipse.glsp.graph.GModelIndex; import org.eclipse.glsp.graph.GNode; import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.operations.AbstractOperationHandler; import org.eclipse.glsp.server.operations.DeleteOperation; - -import com.google.inject.Inject; +import org.eclipse.glsp.server.operations.GModelOperationHandler; /** * Applies {@link DeleteOperation} directly to the GModel. */ -public class GModelDeleteOperationHandler extends AbstractOperationHandler { +public class GModelDeleteOperationHandler extends GModelOperationHandler { private static Logger LOGGER = LogManager.getLogger(GModelDeleteOperationHandler.class); protected Set allDependantsIds; - @Inject - protected GModelState modelState; - @Override - public void executeOperation(final DeleteOperation operation) { + public Optional createCommand(final DeleteOperation operation) { List elementIds = operation.getElementIds(); if (elementIds == null || elementIds.size() == 0) { LOGGER.warn("Elements to delete are not specified"); - return; + return doNothing(); } + return commandOf(() -> deleteElements(elementIds)); + } + + public void deleteElements(final List elementIds) { GModelIndex index = modelState.getIndex(); allDependantsIds = new HashSet<>(); boolean success = elementIds.stream().allMatch(eId -> delete(eId, index)); diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelDiagramModule.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelDiagramModule.java index 07a352d7..2753087c 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelDiagramModule.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelDiagramModule.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2021-2022 EclipseSource and others. + * Copyright (c) 2021-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -58,7 +58,7 @@ protected void configureActionHandlers(final MultiBinding binding } @Override - protected void configureOperationHandlers(final MultiBinding binding) { + protected void configureOperationHandlers(final MultiBinding> binding) { super.configureOperationHandlers(binding); binding.add(GModelApplyLabelEditOperationHandler.class); binding.add(GModelChangeBoundsOperationHandler.class); diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelPasteOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelPasteOperationHandler.java index f67d1d5f..29758f10 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelPasteOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/gmodel/GModelPasteOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2022 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -27,15 +27,16 @@ import java.util.UUID; import java.util.stream.Collectors; +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.graph.GBoundsAware; import org.eclipse.glsp.graph.GEdge; import org.eclipse.glsp.graph.GModelElement; import org.eclipse.glsp.graph.GPoint; import org.eclipse.glsp.graph.impl.GPointImpl; import org.eclipse.glsp.server.gson.GraphGsonConfigurationFactory; -import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.operations.AbstractOperationHandler; +import org.eclipse.glsp.server.operations.GModelOperationHandler; import org.eclipse.glsp.server.operations.PasteOperation; +import org.eclipse.glsp.server.types.EditorContext; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -46,13 +47,10 @@ * * @see GModelRequestClipboardDataActionHandler */ -public class GModelPasteOperationHandler extends AbstractOperationHandler { +public class GModelPasteOperationHandler extends GModelOperationHandler { private static final int DEFAULT_OFFSET = 20; - @Inject - protected GModelState modelState; - protected final Gson gson; @Inject @@ -62,10 +60,14 @@ public GModelPasteOperationHandler(final GraphGsonConfigurationFactory gsonConfi } @Override - public void executeOperation(final PasteOperation operation) { + public Optional createCommand(final PasteOperation operation) { List elements = getCopiedElements(operation.getClipboardData().get("application/json")); + return elements.isEmpty() ? doNothing() + : commandOf(() -> executePaste(elements, operation.getEditorContext())); + } - shift(elements, computeOffset(elements, operation.getEditorContext().getLastMousePosition())); + public void executePaste(final List elements, final EditorContext context) { + shift(elements, computeOffset(elements, context.getLastMousePosition())); Map idMap = reassignIds(elements); filterElements(elements, idMap); @@ -139,4 +141,5 @@ protected void rewireEdges(final List elements, final Map { - - @Inject - protected GModelState modelState; +public class GModelReconnectEdgeOperationHandler extends GModelOperationHandler { @Override + public Optional createCommand(final ReconnectEdgeOperation operation) { + return commandOf(() -> executeReconnect(operation)); + } + @SuppressWarnings("checkstyle:CyclomaticComplexity") - public void executeOperation(final ReconnectEdgeOperation operation) { + protected void executeReconnect(final ReconnectEdgeOperation operation) { if (operation.getEdgeElementId() == null || operation.getSourceElementId() == null || operation.getTargetElementId() == null) { diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/diagram/DefaultServerConfigurationContribution.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/diagram/DefaultServerConfigurationContribution.java index 63065400..8f4f8f49 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/diagram/DefaultServerConfigurationContribution.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/diagram/DefaultServerConfigurationContribution.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2021-2022 EclipseSource and others. + * Copyright (c) 2021-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -48,7 +48,7 @@ public class DefaultServerConfigurationContribution implements ServerConfigurati protected Set actionHandlers; @Inject - protected Set operationHandlers; + protected Set> operationHandlers; @Inject @Named(CLIENT_ACTIONS) diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/operations/DefaultOperationHandlerRegistry.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/operations/DefaultOperationHandlerRegistry.java index e112a858..d8672d54 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/operations/DefaultOperationHandlerRegistry.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/operations/DefaultOperationHandlerRegistry.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2021 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -34,11 +34,11 @@ public class DefaultOperationHandlerRegistry implements OperationHandlerRegistry { - private final MapRegistry internalRegistry; + private final MapRegistry> internalRegistry; private final Map operations; @Inject - public DefaultOperationHandlerRegistry(final Set handlers) { + public DefaultOperationHandlerRegistry(final Set> handlers) { operations = new HashMap<>(); internalRegistry = new MapRegistry<>() {}; handlers.forEach(handler -> { @@ -61,9 +61,9 @@ protected String deriveKey(final Operation key, final String elementTypeId) { } @Override - public boolean register(final Operation key, final OperationHandler handler) { + public boolean register(final Operation key, final OperationHandler handler) { if (handler instanceof CreateOperationHandler) { - return ((CreateOperationHandler) handler).getHandledElementTypeIds().stream() + return ((CreateOperationHandler) handler).getHandledElementTypeIds().stream() .allMatch(typeId -> internalRegistry.register(deriveKey(key, typeId), handler)); } @@ -83,12 +83,12 @@ public boolean hasKey(final Operation key) { } @Override - public Optional get(final Operation key) { + public Optional> get(final Operation key) { return internalRegistry.get(deriveKey(key)); } @Override - public Set getAll() { return internalRegistry.getAll(); } + public Set> getAll() { return internalRegistry.getAll(); } @Override public Set keys() { diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/toolpalette/DefaultToolPaletteItemProvider.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/toolpalette/DefaultToolPaletteItemProvider.java index e989481e..1c662b49 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/toolpalette/DefaultToolPaletteItemProvider.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/toolpalette/DefaultToolPaletteItemProvider.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2021 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -38,12 +38,14 @@ public class DefaultToolPaletteItemProvider implements ToolPaletteItemProvider { protected OperationHandlerRegistry operationHandlerRegistry; private int counter; + @SuppressWarnings("rawtypes") @Override public List getItems(final Map args) { List handlers = operationHandlerRegistry.getAll().stream() .filter(CreateOperationHandler.class::isInstance) .map(CreateOperationHandler.class::cast) .collect(Collectors.toList()); + counter = 0; List nodes = createPaletteItems(handlers, CreateNodeOperation.class); List edges = createPaletteItems(handlers, CreateEdgeOperation.class); @@ -53,11 +55,12 @@ public List getItems(final Map args) { } + @SuppressWarnings({ "rawtypes", "unchecked" }) protected List createPaletteItems(final List handlers, final Class operationClass) { return handlers.stream() - .filter(h -> operationClass.isAssignableFrom(h.getHandledOperationType())) - .flatMap(handler -> handler.getTriggerActions() + .filter(handler -> operationClass.isAssignableFrom(handler.getHandledOperationType())) + .flatMap(handler -> ((List) handler.getTriggerActions()) .stream() .map(action -> create(action, handler.getLabel()))) .sorted(Comparator.comparing(PaletteItem::getLabel)) diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/AbstractCreateOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/AbstractCreateOperationHandler.java index 8733f166..085d0691 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/AbstractCreateOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/AbstractCreateOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2022 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -17,10 +17,16 @@ import java.util.List; +import org.eclipse.glsp.server.gmodel.GModelCreateOperationHandler; + import com.google.common.collect.Lists; +/** + * @deprecated Use {@link GModelCreateOperationHandler} + */ +@Deprecated public abstract class AbstractCreateOperationHandler extends AbstractOperationHandler - implements CreateOperationHandler { + implements CreateOperationHandler { protected List handledElementTypeIds; diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/AbstractOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/AbstractOperationHandler.java index 10d8f0ce..42cd468e 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/AbstractOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/AbstractOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2022 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,7 +15,9 @@ ********************************************************************************/ package org.eclipse.glsp.server.operations; -import org.eclipse.glsp.server.internal.util.GenericsUtil; +import java.util.Optional; + +import org.eclipse.emf.common.command.Command; /** * Basic {@link OperationHandler} implementation that can handle exactly one {@link Operation} type. @@ -25,32 +27,27 @@ * and can work directly with the correct subtype instead of having to manually cast it. * * @param class of the handled action type + * + * @deprecated Use {@link GModelOperationHandler} with optional command instead. */ -public abstract class AbstractOperationHandler implements OperationHandler { - - protected final Class operationType; - - public AbstractOperationHandler() { - this.operationType = deriveOperationType(); - } - - @SuppressWarnings("unchecked") - protected Class deriveOperationType() { - return (Class) GenericsUtil.getActualTypeArgument(getClass(), Operation.class); - } - +@Deprecated +public abstract class AbstractOperationHandler extends GModelOperationHandler { @Override - public Class getHandledOperationType() { return operationType; } + public Optional createCommand(final O operation) { + return preExecute(operation) ? commandOf(() -> executeOperation(operation)) : doNothing(); + } - @Override - public void execute(final Operation operation) { - if (handles(operation)) { - executeOperation(operationType.cast(operation)); - } + /** + * Returns whether the execution of the operation should continue. If false is returned, + * {@link #executeOperation(Operation)} is not called and no update is performed on the model. Otherwise, the + * execution continues normally and the model will be updated and marked dirty. + * + * @param operation operation + * @return true if the execution should continue, false if we should abort the execution. + */ + protected boolean preExecute(final O operation) { + return true; } protected abstract void executeOperation(O operation); - - @Override - public String getLabel() { return operationType.getSimpleName(); } } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/BasicOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/BasicOperationHandler.java index 16177d02..fc5d41d6 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/BasicOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/BasicOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2022 EclipseSource and others. + * Copyright (c) 2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,25 +15,36 @@ ********************************************************************************/ package org.eclipse.glsp.server.operations; +import java.util.Optional; + +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.server.model.GModelState; import com.google.inject.Inject; -/** - * Deprecated, will be removed with version 1.0. - * Please use {@link AbstractOperationHandler} instead and directly inject the {@link GModelState}. - */ -@Deprecated -public abstract class BasicOperationHandler extends AbstractOperationHandler { +public abstract class BasicOperationHandler implements OperationHandler { + + protected final Class operationType; @Inject protected GModelState modelState; + public BasicOperationHandler() { + this.operationType = OperationHandler.super.getHandledOperationType(); + } + @Override - protected void executeOperation(final T operation) { - executeOperation(operation, modelState); + public boolean handles(final Operation operation) { + return modelState.getRoot() != null && OperationHandler.super.handles(operation); } - protected abstract void executeOperation(T operation, GModelState modelState); + @Override + public Class getHandledOperationType() { return operationType; } + + @Override + public String getLabel() { return operationType.getSimpleName(); } + protected static Optional doNothing() { + return Optional.empty(); + } } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CompoundOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CompoundOperationHandler.java index f14d0e25..e2663509 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CompoundOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CompoundOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2022 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,19 +15,22 @@ ********************************************************************************/ package org.eclipse.glsp.server.operations; +import java.util.Optional; + +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CompoundCommand; + import com.google.inject.Inject; -public class CompoundOperationHandler extends AbstractOperationHandler { +public class CompoundOperationHandler extends BasicOperationHandler { @Inject protected OperationHandlerRegistry operationHandlerRegistry; @Override - protected void executeOperation(final CompoundOperation operation) { - operation.getOperationList().forEach(nestedOperation -> executeNestedOperation(nestedOperation)); + public Optional createCommand(final CompoundOperation operation) { + CompoundCommand command = new CompoundCommand(); + operation.getOperationList().forEach( + childOperation -> operationHandlerRegistry.getExecutableCommand(childOperation).ifPresent(command::append)); + return command.getCommandList().isEmpty() ? Optional.empty() : Optional.of(command); } - - protected void executeNestedOperation(final Operation operation) { - operationHandlerRegistry.getOperationHandler(operation).ifPresent(handler -> handler.execute(operation)); - } - } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateEdgeOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateEdgeOperationHandler.java index f63638da..2b50950f 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateEdgeOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateEdgeOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 EclipseSource and others. + * Copyright (c) 2022-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,7 +15,4 @@ ********************************************************************************/ package org.eclipse.glsp.server.operations; -public interface CreateEdgeOperationHandler extends CreateOperationHandler { - @Override - Class getHandledOperationType(); -} +public interface CreateEdgeOperationHandler extends CreateOperationHandler {} diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateNodeOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateNodeOperationHandler.java index 2e506f99..98915331 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateNodeOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateNodeOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 EclipseSource and others. + * Copyright (c) 2022-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -21,9 +21,7 @@ import org.eclipse.glsp.graph.GPoint; import org.eclipse.glsp.server.utils.LayoutUtil; -public interface CreateNodeOperationHandler extends CreateOperationHandler { - @Override - Class getHandledOperationType(); +public interface CreateNodeOperationHandler extends CreateOperationHandler { /** * Return the absolute location where the element should be created. diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateOperationHandler.java index fc6934af..915bdd3e 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CreateOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2022 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -28,15 +28,7 @@ * A special {@link OperationHandler} that is responsible for the handling of {@link CreateOperation}s. Depending on its * operation type the triggered actions are {@link TriggerNodeCreationAction} or {@link TriggerEdgeCreationAction}s. */ -public interface CreateOperationHandler extends OperationHandler { - - /** - * Returns the {@link CreateOperation} type this handler has registered for. - * - * @return The {@link CreateOperation} type this handler has registered for. - */ - @Override - Class getHandledOperationType(); +public interface CreateOperationHandler extends OperationHandler { /** * Returns a list of {@link TriggerElementCreationAction}s for registered element types. diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CutOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CutOperationHandler.java index 0f87dc57..ea29d96f 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CutOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/CutOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020-2022 EclipseSource and others. + * Copyright (c) 2020-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -16,7 +16,9 @@ package org.eclipse.glsp.server.operations; import java.util.List; +import java.util.Optional; +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.server.actions.ActionDispatcher; import com.google.inject.Inject; @@ -24,20 +26,20 @@ /** * Performs the cut operation by dispatching a {@link DeleteOperation} for the elements to be cut. */ -public class CutOperationHandler extends AbstractOperationHandler { +public class CutOperationHandler extends GModelOperationHandler { @Inject protected ActionDispatcher actionDispatcher; - @Override - public void executeOperation(final CutOperation operation) { - List cutableElementIds = getElementToCut(operation); - if (!cutableElementIds.isEmpty()) { - actionDispatcher.dispatch(new DeleteOperation(cutableElementIds)); - } + protected List getElementsToCut(final CutOperation cutAction) { + return cutAction.getEditorContext().getSelectedElementIds(); } - protected List getElementToCut(final CutOperation cutAction) { - return cutAction.getEditorContext().getSelectedElementIds(); + @Override + public Optional createCommand(final CutOperation operation) { + List elementsToCut = getElementsToCut(operation); + return elementsToCut.isEmpty() + ? doNothing() + : commandOf(() -> actionDispatcher.dispatch(new DeleteOperation(elementsToCut))); } } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/GModelOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/GModelOperationHandler.java new file mode 100644 index 00000000..72887407 --- /dev/null +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/GModelOperationHandler.java @@ -0,0 +1,32 @@ +/******************************************************************************** + * Copyright (c) 2023 EclipseSource and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +package org.eclipse.glsp.server.operations; + +import java.util.Optional; + +import org.eclipse.emf.common.command.Command; +import org.eclipse.glsp.server.internal.gmodel.commandstack.GModelRecordingCommand; + +public abstract class GModelOperationHandler extends BasicOperationHandler { + + protected Optional commandOf(final Runnable runnable) { + return Optional.of(recordingCommand(runnable)); + } + + protected Command recordingCommand(final Runnable runnable) { + return new GModelRecordingCommand(modelState.getRoot(), getLabel(), runnable); + } +} diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/LayoutOperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/LayoutOperationHandler.java index b9c83e10..8978a317 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/LayoutOperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/LayoutOperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -17,6 +17,7 @@ import java.util.Optional; +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.server.diagram.DiagramConfiguration; import org.eclipse.glsp.server.layout.LayoutEngine; import org.eclipse.glsp.server.layout.ServerLayoutKind; @@ -26,7 +27,7 @@ /** * Delegates to the configured {@link LayoutEngine} to apply a layout. */ -public class LayoutOperationHandler extends AbstractOperationHandler { +public class LayoutOperationHandler extends GModelOperationHandler { @Inject protected Optional layoutEngine; @@ -35,12 +36,10 @@ public class LayoutOperationHandler extends AbstractOperationHandler createCommand(final LayoutOperation operation) { + return layoutEngine.isEmpty() || diagramConfiguration.getLayoutKind() != ServerLayoutKind.MANUAL + ? doNothing() + : commandOf(() -> layoutEngine.get().layout()); } } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationActionHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationActionHandler.java index 80e32b38..30b0d059 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationActionHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -18,11 +18,11 @@ import java.util.List; import java.util.Optional; +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.server.actions.AbstractActionHandler; import org.eclipse.glsp.server.actions.Action; import org.eclipse.glsp.server.actions.SetDirtyStateAction; import org.eclipse.glsp.server.features.core.model.ModelSubmissionHandler; -import org.eclipse.glsp.server.internal.gmodel.commandstack.GModelRecordingCommand; import org.eclipse.glsp.server.model.GModelState; import org.eclipse.glsp.server.utils.ServerMessageUtil; @@ -59,10 +59,20 @@ protected List executeOperation(final Operation operation) { .orElseGet(this::none); } - protected List executeHandler(final Operation operation, final OperationHandler handler) { - GModelRecordingCommand command = new GModelRecordingCommand(modelState.getRoot(), handler.getLabel(), - () -> handler.execute(operation)); + protected List executeHandler(final Operation operation, final OperationHandler handler) { + Optional command = handler.execute(operation); + if (command.isPresent()) { + exexcuteCommand(command.get()); + return submitModel(); + } + return none(); + } + + protected void exexcuteCommand(final Command command) { modelState.execute(command); + } + + protected List submitModel() { return modelSubmissionHandler.submitModel(SetDirtyStateAction.Reason.OPERATION); } @@ -70,7 +80,7 @@ protected List executeHandler(final Operation operation, final Operation * Use {@link OperationHandlerRegistry#getOperationHandler(Operation) instead}. */ @Deprecated - public static Optional getOperationHandler(final Operation operation, + public static Optional> getOperationHandler(final Operation operation, final OperationHandlerRegistry registry) { return registry.getOperationHandler(operation); } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationHandler.java index 41f4599c..a41c31ec 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019-2021 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,10 +15,12 @@ ******************************************************************************/ package org.eclipse.glsp.server.operations; +import java.util.Optional; + import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.server.actions.ActionDispatcher; +import org.eclipse.glsp.server.internal.util.GenericsUtil; import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.types.GLSPServerException; /** * An operation handler can execute {@link Operation}s of a certain type (subclass). @@ -32,24 +34,40 @@ * The {@link OperationActionHandler} is responsible for retrieving all available (valid) operation handlers for an * operation that is dispatched via {@link ActionDispatcher}. */ -public interface OperationHandler { +public interface OperationHandler { /** * Returns the class of the operation type that can be handled by this operation handler. * * @return the {@link Operation} (sub)class that can be handled. */ - Class getHandledOperationType(); + @SuppressWarnings("unchecked") + default Class getHandledOperationType() { + return (Class) GenericsUtil.getActualTypeArgument(getClass(), Operation.class); + } - String getLabel(); + default String getLabel() { return getHandledOperationType().getSimpleName(); } /** - * Executes the operation handler for the given {@link Operation} If the given action cannot be handled by this - * operation handler a {@link GLSPServerException} is thrown. + * Creates a command that performs the operation in the source model(s). If an empty command is returned, no update + * is performed on the model(s). * - * @param operation The operation that should be executed. + * @param operation The operation to process. + * @return The created command to be executed on the command stack or empty if nothing should be done. */ - void execute(Operation operation); + Optional createCommand(O operation); + + /** + * Executes the operation handler for the given {@link Operation}. If the given action cannot be handled by this + * operation handler an empty command is returned an no changes are executed. + * + * @param operation The operation that should be executed or empty if nothing should be done. + */ + default Optional execute(final Operation operation) { + return handles(operation) + ? createCommand(getHandledOperationType().cast(operation)) + : Optional.empty(); + } /** * Validates whether the given {@link Operation} can be handled by this operation handler. diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationHandlerRegistry.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationHandlerRegistry.java index 7900ff59..e1989eed 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationHandlerRegistry.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationHandlerRegistry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019-2022 EclipseSource and others. + * Copyright (c) 2019-2023 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -17,21 +17,35 @@ import java.util.Optional; +import org.eclipse.emf.common.command.Command; import org.eclipse.glsp.server.registry.Registry; /** * This registry contains {@link OperationHandler}s that are registered for certain {@link Operation} types. */ -public interface OperationHandlerRegistry extends Registry { - default Optional getOperationHandler(final Operation operation) { - Optional operationHandler = get(operation); +public interface OperationHandlerRegistry extends Registry> { + default Optional> getOperationHandler(final Operation operation) { + Optional> operationHandler = get(operation); if (operation instanceof CreateOperation) { // create operations need to be handled by create operation handlers that support the element type id CreateOperation createOperation = (CreateOperation) operation; - return operationHandler.filter(CreateOperationHandler.class::isInstance) + return operationHandler + .filter(CreateOperationHandler.class::isInstance) .map(CreateOperationHandler.class::cast) - .filter(handler -> handler.getHandledElementTypeIds().contains(createOperation.getElementTypeId())); + .filter(handler -> handler.getHandledElementTypeIds().contains(createOperation.getElementTypeId())) + .map(OperationHandler.class::cast); } return operationHandler; } + + /** + * Returns the matching command for the given operation. + * + * @param registry operation handler registry + * @param operation operation + * @return the matching command for the given operation + */ + default Optional getExecutableCommand(final Operation operation) { + return getOperationHandler(operation).flatMap(handler -> handler.execute(operation)); + } }