diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/Action.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/Action.java index 7d981b17..724fa2f9 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/Action.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/Action.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,6 +15,8 @@ ********************************************************************************/ package org.eclipse.glsp.server.actions; +import org.eclipse.glsp.server.protocol.GLSPServer; + /** * Java-implementation of the `Action` interface. An action is a declarative description of a behavior that * shall be @@ -31,6 +33,13 @@ public abstract class Action { */ private final String kind; + /** + * Optional boolean flag that marks actions that have + * been received from the client. Is set automatically by the {@link GLSPServer} + * for every received action. + */ + private boolean receivedFromClient; + public Action(final String kind) { super(); this.kind = kind; @@ -38,6 +47,10 @@ public Action(final String kind) { public String getKind() { return kind; } + public boolean isReceivedFromClient() { return receivedFromClient; } + + public void setReceivedFromClient(final boolean receivedFromClient) { this.receivedFromClient = receivedFromClient; } + @Override public String toString() { StringBuilder builder = new StringBuilder(); diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ActionRegistry.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ActionRegistry.java index 72245bc1..2bcd54f2 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ActionRegistry.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ActionRegistry.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 @@ -25,17 +25,6 @@ */ public interface ActionRegistry extends Registry>> { - /** - * Registers an action for a diagramType. - * - * @param diagramType The diagramType for which the action is registered. - * @param actionKind The actionKind of the action to be registered. - * @param action The action to be registered. - * @param isServerAction This flag indicates if the given action is handled by the server. - * @return A boolean flag that indicates if the registration was successful. - */ - boolean register(String diagramType, String actionKind, Class action, boolean isServerAction); - /** * Registers a server handled action for a diagramType. * @@ -44,9 +33,7 @@ public interface ActionRegistry extends Registry action) { - return register(diagramType, actionKind, action, true); - } + boolean register(String diagramType, String actionKind, Class action); /** * Registers a set of server handled actions for a diagramType. @@ -56,34 +43,21 @@ default boolean register(final String diagramType, final String actionKind, fina * @return A boolean flag that indicates if the registration was successful. */ @Override - default boolean register(final String diagramType, final Map> actionMap) { - return register(diagramType, actionMap, true); - } - - /** - * Registers a set of actions for a diagramType. - * - * @param diagramType The diagramType for which the action is registered. - * @param actionMap A map of actionKind and actions to be registered. - * @param isServerAction This flag indicates if the given actions are handled by the server. - * @return A boolean flag that indicates if the registration was successful. - */ - boolean register(String diagramType, Map> actionMap, - boolean isServerAction); + boolean register(String diagramType, Map> actionMap); /** - * Returns a list of actions that are handled by the server for the given diagramType. + * Returns a list of actions kinds that are handled by the server for the given diagramType. * * @return A list of actions that are handled on the server for the given diagramType. */ - List getServerHandledAction(String diagramType); + List getHandledActionKinds(String diagramType); /** - * Returns a map of all registered diagramTypes and their server-handled actions. + * Returns a map of all registered diagramTypes and their server-handled actions kinds. * * @return A map of all registered diagramTypes and their server-handled actions. */ - Map> getServerHandledActions(); + Map> getHandledActionKinds(); /** * Returns a map of all currently registered actionKinds and their corresponding {@link Action} class. diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ClientActionForwarder.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ClientActionForwarder.java new file mode 100644 index 00000000..94696cdb --- /dev/null +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ClientActionForwarder.java @@ -0,0 +1,82 @@ +/******************************************************************************** + * 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 + * 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.actions; + +import static org.eclipse.glsp.server.di.ClientSessionModule.CLIENT_ACTIONS; + +import java.util.Set; + +import org.eclipse.glsp.server.di.ClientId; +import org.eclipse.glsp.server.di.DiagramType; +import org.eclipse.glsp.server.model.GModelState; +import org.eclipse.glsp.server.protocol.GLSPClient; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import com.google.inject.name.Named; + +/** + * Component responsible for forwarding actions that are (also) handled by the + * client. + */ +@Singleton +public class ClientActionForwarder { + + @Inject + protected Provider client; + + @Inject + protected GModelState modelState; + + @Inject + @ClientId + protected String clientId; + + @Inject + @DiagramType + protected String diagramType; + + @Inject + @Named(CLIENT_ACTIONS) + protected Set clientActionKinds; + + /** + * Processes the given action and checks wether it is a + * `clientAction` i.e. andaction that should be forwared to + * the client to be handled there. If the check is successful + * the action is wrapped in an {@link ActionMessage} and sent to the client. + * + * @param action The action to check and forward + * @return `true` if the action was forwared to the client, `false` otherwise + */ + public boolean handle(final Action action) { + if (shouldForwardToClient(action)) { + ActionMessage message = new ActionMessage(clientId, action); + client.get().process(message); + return true; + } + return false; + } + + protected boolean shouldForwardToClient(final Action action) { + if (action.isReceivedFromClient()) { + return false; + } + return (clientActionKinds.contains(action.getKind()) || action instanceof ResponseAction); + } + +} diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ClientActionHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ClientActionHandler.java deleted file mode 100644 index 32907b64..00000000 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/ClientActionHandler.java +++ /dev/null @@ -1,67 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2020-2022 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.actions; - -import static org.eclipse.glsp.server.di.GLSPModule.CLIENT_ACTIONS; - -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.eclipse.glsp.server.model.GModelState; -import org.eclipse.glsp.server.protocol.GLSPClient; - -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.google.inject.name.Named; - -/** - * Action handler for client actions. - * - * This action handler is registered for all actions that are handled on the - * client and sends them to the client on execution. - */ -public class ClientActionHandler implements ActionHandler { - - @Inject - protected Provider client; - - @Inject - protected GModelState modelState; - - private final List> handledActionTypes; - - @Inject - public ClientActionHandler(@Named(CLIENT_ACTIONS) final Set clientActions) { - this.handledActionTypes = clientActions.stream().map(Action::getClass).collect(Collectors.toList()); - } - - @Override - public List> getHandledActionTypes() { return handledActionTypes; } - - @Override - public List execute(final Action action) { - send(modelState.getClientId(), action); - return Collections.emptyList(); - } - - protected void send(final String clientId, final Action action) { - ActionMessage message = new ActionMessage(clientId, action); - client.get().process(message); - } - -} diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/ClientIdModule.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/ClientSessionModule.java similarity index 61% rename from plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/ClientIdModule.java rename to plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/ClientSessionModule.java index bde6beee..337ab971 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/ClientIdModule.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/ClientSessionModule.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2021 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 @@ -15,22 +15,33 @@ ********************************************************************************/ package org.eclipse.glsp.server.di; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + import com.google.inject.AbstractModule; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; /** * Helper module that is typically combined a{@link DiagramModule} to make the - * client session id available in the injector. + * client session specific configuration available in the injector. */ -public class ClientIdModule extends AbstractModule { +public class ClientSessionModule extends AbstractModule { + public static final String CLIENT_ACTIONS = "ClientActions"; + protected final String clientId; + protected final Set clientActionKinds; - public ClientIdModule(final String clientId) { + public ClientSessionModule(final String clientId, final Collection clientActionKinds) { this.clientId = clientId; + this.clientActionKinds = new HashSet<>(clientActionKinds); } @Override protected void configure() { bind(String.class).annotatedWith(ClientId.class).toInstance(clientId); + bind(new TypeLiteral>() {}).annotatedWith(Names.named(CLIENT_ACTIONS)).toInstance(clientActionKinds); } } 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 6f9c931a..e790aa5f 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 @@ -22,73 +22,40 @@ import org.eclipse.glsp.server.actions.ActionDispatcher; import org.eclipse.glsp.server.actions.ActionHandler; import org.eclipse.glsp.server.actions.ActionHandlerRegistry; -import org.eclipse.glsp.server.actions.CenterAction; -import org.eclipse.glsp.server.actions.ClientActionHandler; -import org.eclipse.glsp.server.actions.EndProgressAction; -import org.eclipse.glsp.server.actions.ExportSVGAction; -import org.eclipse.glsp.server.actions.FitToScreenAction; -import org.eclipse.glsp.server.actions.RejectAction; import org.eclipse.glsp.server.actions.SaveModelActionHandler; -import org.eclipse.glsp.server.actions.SelectAction; -import org.eclipse.glsp.server.actions.SelectAllAction; -import org.eclipse.glsp.server.actions.ServerMessageAction; -import org.eclipse.glsp.server.actions.ServerStatusAction; -import org.eclipse.glsp.server.actions.SetDirtyStateAction; -import org.eclipse.glsp.server.actions.SetEditModeAction; import org.eclipse.glsp.server.actions.SetEditModeActionHandler; -import org.eclipse.glsp.server.actions.SetViewportAction; -import org.eclipse.glsp.server.actions.StartProgressAction; -import org.eclipse.glsp.server.actions.TriggerEdgeCreationAction; -import org.eclipse.glsp.server.actions.TriggerNodeCreationAction; -import org.eclipse.glsp.server.actions.UpdateProgressAction; import org.eclipse.glsp.server.di.scope.DiagramGlobalScope; import org.eclipse.glsp.server.di.scope.DiagramGlobalSingleton; import org.eclipse.glsp.server.diagram.DiagramConfiguration; import org.eclipse.glsp.server.diagram.RequestTypeHintsActionHandler; import org.eclipse.glsp.server.diagram.ServerConfigurationContribution; -import org.eclipse.glsp.server.diagram.SetTypeHintsAction; -import org.eclipse.glsp.server.features.clipboard.SetClipboardDataAction; import org.eclipse.glsp.server.features.commandpalette.CommandPaletteActionProvider; import org.eclipse.glsp.server.features.contextactions.ContextActionsProvider; import org.eclipse.glsp.server.features.contextactions.ContextActionsProviderRegistry; import org.eclipse.glsp.server.features.contextactions.RequestContextActionsHandler; -import org.eclipse.glsp.server.features.contextactions.SetContextActions; import org.eclipse.glsp.server.features.contextmenu.ContextMenuItemProvider; import org.eclipse.glsp.server.features.core.model.ComputedBoundsActionHandler; import org.eclipse.glsp.server.features.core.model.GModelFactory; -import org.eclipse.glsp.server.features.core.model.RequestBoundsAction; import org.eclipse.glsp.server.features.core.model.RequestModelActionHandler; -import org.eclipse.glsp.server.features.core.model.SetBoundsAction; -import org.eclipse.glsp.server.features.core.model.SetModelAction; import org.eclipse.glsp.server.features.core.model.SourceModelStorage; -import org.eclipse.glsp.server.features.core.model.UpdateModelAction; import org.eclipse.glsp.server.features.directediting.ContextEditValidator; import org.eclipse.glsp.server.features.directediting.ContextEditValidatorRegistry; import org.eclipse.glsp.server.features.directediting.LabelEditValidator; import org.eclipse.glsp.server.features.directediting.RequestEditValidationHandler; -import org.eclipse.glsp.server.features.directediting.SetEditValidationResultAction; -import org.eclipse.glsp.server.features.navigation.NavigateToExternalTargetAction; -import org.eclipse.glsp.server.features.navigation.NavigateToTargetAction; import org.eclipse.glsp.server.features.navigation.NavigationTargetProvider; import org.eclipse.glsp.server.features.navigation.NavigationTargetProviderRegistry; import org.eclipse.glsp.server.features.navigation.NavigationTargetResolver; import org.eclipse.glsp.server.features.navigation.RequestNavigationTargetsActionHandler; import org.eclipse.glsp.server.features.navigation.ResolveNavigationTargetActionHandler; -import org.eclipse.glsp.server.features.navigation.SetNavigationTargetsAction; -import org.eclipse.glsp.server.features.navigation.SetResolvedNavigationTargetAction; import org.eclipse.glsp.server.features.popup.PopupModelFactory; import org.eclipse.glsp.server.features.popup.RequestPopupModelActionHandler; -import org.eclipse.glsp.server.features.popup.SetPopupModelAction; import org.eclipse.glsp.server.features.progress.DefaultProgressService; import org.eclipse.glsp.server.features.progress.ProgressService; -import org.eclipse.glsp.server.features.sourcemodelwatcher.SourceModelChangedAction; import org.eclipse.glsp.server.features.sourcemodelwatcher.SourceModelWatcher; import org.eclipse.glsp.server.features.toolpalette.ToolPaletteItemProvider; import org.eclipse.glsp.server.features.undoredo.UndoRedoActionHandler; -import org.eclipse.glsp.server.features.validation.DeleteMarkersAction; import org.eclipse.glsp.server.features.validation.ModelValidator; import org.eclipse.glsp.server.features.validation.RequestMarkersHandler; -import org.eclipse.glsp.server.features.validation.SetMarkersAction; import org.eclipse.glsp.server.gmodel.GModelCutOperationHandler; import org.eclipse.glsp.server.gson.GraphGsonConfigurationFactory; import org.eclipse.glsp.server.internal.actions.DefaultActionDispatcher; @@ -174,6 +141,7 @@ protected void configureBase() { bindDiagramType(); bindClientId(); bindDiagramGobalScope(); + // Configurations bind(DiagramConfiguration.class).to(bindDiagramConfiguration()).in(DiagramGlobalSingleton.class); bind(ServerConfigurationContribution.class).to(bindServerConfigurationContribution()).in(Singleton.class); @@ -198,7 +166,6 @@ protected void configureBase() { // Action & Operation related bindings bind(ActionDispatcher.class).to(bindActionDispatcher()).in(Singleton.class); - 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(new TypeLiteral>() {}), this::configureOperationHandlers); @@ -289,43 +256,7 @@ protected Class bindActionDispatcher() { return DefaultActionDispatcher.class; } - protected void configureClientActions(final MultiBinding binding) { - binding.add(CenterAction.class); - binding.add(DeleteMarkersAction.class); - binding.add(EndProgressAction.class); - binding.add(ExportSVGAction.class); - binding.add(FitToScreenAction.class); - binding.add(NavigateToExternalTargetAction.class); - binding.add(NavigateToTargetAction.class); - binding.add(RejectAction.class); - binding.add(RequestBoundsAction.class); - binding.add(SelectAction.class); - binding.add(SelectAllAction.class); - binding.add(ServerMessageAction.class); - binding.add(ServerStatusAction.class); - binding.add(SetBoundsAction.class); - binding.add(SetClipboardDataAction.class); - binding.add(SetContextActions.class); - binding.add(SetDirtyStateAction.class); - binding.add(SetEditModeAction.class); - binding.add(SetEditValidationResultAction.class); - binding.add(SetMarkersAction.class); - binding.add(SetModelAction.class); - binding.add(SetNavigationTargetsAction.class); - binding.add(SetPopupModelAction.class); - binding.add(SetResolvedNavigationTargetAction.class); - binding.add(SetTypeHintsAction.class); - binding.add(SetViewportAction.class); - binding.add(SourceModelChangedAction.class); - binding.add(StartProgressAction.class); - binding.add(TriggerEdgeCreationAction.class); - binding.add(TriggerNodeCreationAction.class); - binding.add(UpdateModelAction.class); - binding.add(UpdateProgressAction.class); - } - protected void configureActionHandlers(final MultiBinding binding) { - binding.add(ClientActionHandler.class); binding.add(DefaultActionDispatcher.class); binding.add(OperationActionHandler.class); binding.add(RequestModelActionHandler.class); diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/GLSPModule.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/GLSPModule.java index b46e6e5b..89e4e1d9 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/GLSPModule.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/di/GLSPModule.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2021 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 @@ -29,7 +29,6 @@ * Common super class for GLSP guice {@link Module}s. */ public abstract class GLSPModule extends AbstractModule { - public static final String CLIENT_ACTIONS = "ClientActions"; /** * Splits the configure method in two phases. The "configureBase" sub method diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionDispatcher.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionDispatcher.java index 03d87259..06c32cdd 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionDispatcher.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionDispatcher.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 @@ -34,6 +34,7 @@ import org.eclipse.glsp.server.actions.ActionDispatcher; import org.eclipse.glsp.server.actions.ActionHandler; import org.eclipse.glsp.server.actions.ActionHandlerRegistry; +import org.eclipse.glsp.server.actions.ClientActionForwarder; import org.eclipse.glsp.server.actions.ResponseAction; import org.eclipse.glsp.server.di.ClientId; import org.eclipse.glsp.server.disposable.Disposable; @@ -64,6 +65,9 @@ public class DefaultActionDispatcher extends Disposable implements ActionDispatc @ClientId protected String clientId; + @Inject + protected ClientActionForwarder clientActionForwarder; + protected final String name; protected final Thread thread; @@ -183,8 +187,9 @@ protected void handleAction(final Action action) { } protected List> runAction(final Action action) { + boolean handledOnClient = clientActionForwarder.handle(action); final List actionHandlers = actionHandlerRegistry.get(action); - if (actionHandlers.isEmpty()) { + if (!handledOnClient && actionHandlers.isEmpty()) { throw new IllegalArgumentException("No handler registered for action: " + action); } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionHandlerRegistry.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionHandlerRegistry.java index 60f01888..0a4dd2da 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionHandlerRegistry.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionHandlerRegistry.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 diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionRegistry.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionRegistry.java index c8c6d2f7..6b54e176 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionRegistry.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/actions/DefaultActionRegistry.java @@ -27,16 +27,12 @@ public class DefaultActionRegistry extends MapRegistry>> implements ActionRegistry { - protected Map> serverHandledActionKinds = new HashMap<>(); - @Override - public boolean register(final String diagramType, final String actionKind, final Class actionClass, - final boolean isServerAction) { + public boolean register(final String diagramType, final String actionKind, + final Class actionClass) { Map> actionMap = elements.computeIfAbsent(diagramType, k -> new HashMap<>()); Class existing = actionMap.putIfAbsent(actionKind, actionClass); - if (existing == null && isServerAction) { - serverHandledActionKinds.computeIfAbsent(diagramType, k -> new ArrayList<>()).add(actionKind); - } else if (existing != null && existing != actionClass) { + if (existing != null && existing != actionClass) { throw new IllegalArgumentException( String.format( "Conflicting registration! Another class is already registered for action kind '%s'. Conflicting classes: '%s', '%s'", @@ -46,29 +42,26 @@ public boolean register(final String diagramType, final String actionKind, final } @Override - public boolean register(final String diagramType, final Map> actionMap, - final boolean isServerAction) { + public boolean register(final String diagramType, final Map> actionMap) { return actionMap.entrySet().stream() - .allMatch(entry -> register(diagramType, entry.getKey(), entry.getValue(), isServerAction)); + .allMatch(entry -> register(diagramType, entry.getKey(), entry.getValue())); } @Override - public boolean deregister(final String diagramType) { - boolean deregistered = super.deregister(diagramType); - if (deregistered) { - serverHandledActionKinds.remove(diagramType); - } - return deregistered; + public List getHandledActionKinds(final String diagramType) { + return get(diagramType).map(map -> new ArrayList<>(map.keySet())) + .orElse(new ArrayList<>()); } @Override - public List getServerHandledAction(final String diagramType) { - return serverHandledActionKinds.computeIfAbsent(diagramType, k -> new ArrayList<>()); + public Map> getHandledActionKinds() { + Map> result = new HashMap<>(); + keys().forEach(diagramType -> { + result.put(diagramType, getHandledActionKinds(diagramType)); + }); + return result; } - @Override - public Map> getServerHandledActions() { return serverHandledActionKinds; } - @Override public Map> getAllAsMap() { Map> result = new HashMap<>(); 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 8f4f8f49..48593342 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 @@ -15,8 +15,6 @@ ********************************************************************************/ package org.eclipse.glsp.server.internal.diagram; -import static org.eclipse.glsp.server.di.GLSPModule.CLIENT_ACTIONS; - import java.util.Set; import java.util.stream.Stream; @@ -24,7 +22,6 @@ import org.eclipse.glsp.server.actions.Action; import org.eclipse.glsp.server.actions.ActionHandler; import org.eclipse.glsp.server.actions.ActionRegistry; -import org.eclipse.glsp.server.actions.ClientActionHandler; import org.eclipse.glsp.server.di.DiagramType; import org.eclipse.glsp.server.diagram.ServerConfigurationContribution; import org.eclipse.glsp.server.gson.GraphGsonConfigurationFactory; @@ -33,7 +30,6 @@ import org.eclipse.glsp.server.operations.OperationHandler; import com.google.inject.Inject; -import com.google.inject.name.Named; public class DefaultServerConfigurationContribution implements ServerConfigurationContribution { @@ -50,24 +46,17 @@ public class DefaultServerConfigurationContribution implements ServerConfigurati @Inject protected Set> operationHandlers; - @Inject - @Named(CLIENT_ACTIONS) - protected Set clientActions; - @Override public void configure(final ActionRegistry registry) { Stream handledActions = ReflectionUtil.construct(actionHandlers.stream() - .filter(handler -> !(handler instanceof ClientActionHandler)) .flatMap(h -> h.getHandledActionTypes().stream())); Stream handledOperations = ReflectionUtil.construct(operationHandlers.stream() .map(OperationHandler::getHandledOperationType)); - handledActions.forEach(action -> registry.register(diagramType, action.getKind(), action.getClass(), true)); + handledActions.forEach(action -> registry.register(diagramType, action.getKind(), action.getClass())); handledOperations - .forEach(operation -> registry.register(diagramType, operation.getKind(), operation.getClass(), true)); - - clientActions.forEach(action -> registry.register(diagramType, action.getKind(), action.getClass(), false)); + .forEach(operation -> registry.register(diagramType, operation.getKind(), operation.getClass())); } @Override diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/gson/DefaultServerGsonConfigurator.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/gson/DefaultServerGsonConfigurator.java index 908dac08..4de00e9f 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/gson/DefaultServerGsonConfigurator.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/gson/DefaultServerGsonConfigurator.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 @@ -17,6 +17,7 @@ import static org.eclipse.glsp.server.di.ServerModule.DIAGRAM_MODULES; +import java.util.Collections; import java.util.Map; import org.eclipse.glsp.graph.gson.EnumTypeAdapter; @@ -25,6 +26,7 @@ import org.eclipse.glsp.server.diagram.ServerConfigurationContribution; import org.eclipse.glsp.server.gson.ActionTypeAdapter; import org.eclipse.glsp.server.gson.ServerGsonConfigurator; +import org.eclipse.glsp.server.protocol.InitializeClientSessionParameters; import org.eclipse.glsp.server.session.ClientSession; import org.eclipse.glsp.server.session.ClientSessionManager; @@ -56,7 +58,9 @@ protected void configure(final Map diagramModules, final ClientS // temporary session can be disposed diagramModules.keySet().forEach(diagramType -> { String sessionId = "TempServerConfigurationSession_" + diagramType; - ClientSession session = sessionManager.getOrCreateClientSession(sessionId, diagramType); + InitializeClientSessionParameters params = new InitializeClientSessionParameters(sessionId, diagramType, + Collections.emptyList()); + ClientSession session = sessionManager.getOrCreateClientSession(params); ServerConfigurationContribution contribution = session.getInjector() .getInstance(ServerConfigurationContribution.class); contribution.configure(actionRegistry); diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/session/DefaultClientSessionFactory.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/session/DefaultClientSessionFactory.java index 757a7c22..bbbe8822 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/session/DefaultClientSessionFactory.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/session/DefaultClientSessionFactory.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2021 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 @@ -21,10 +21,11 @@ import java.util.Optional; import org.eclipse.glsp.server.actions.ActionDispatcher; -import org.eclipse.glsp.server.di.ClientIdModule; +import org.eclipse.glsp.server.di.ClientSessionModule; import org.eclipse.glsp.server.di.ServerModule; import org.eclipse.glsp.server.di.scope.DiagramGlobalScope; import org.eclipse.glsp.server.di.scope.DiagramGlobalScopeModule; +import org.eclipse.glsp.server.protocol.InitializeClientSessionParameters; import org.eclipse.glsp.server.session.ClientSession; import org.eclipse.glsp.server.session.ClientSessionFactory; import org.eclipse.glsp.server.utils.ModuleUtil; @@ -47,10 +48,12 @@ public class DefaultClientSessionFactory implements ClientSessionFactory { protected Map diagramModules; @Override - public ClientSession create(final String clientSessionId, final String diagramType) { + public ClientSession create(final InitializeClientSessionParameters params) { + String diagramType = params.getDiagramType(); + String clientSessionId = params.getClientSessionId(); Module diagramModule = getOrThrow(Optional.of(diagramModules.get(diagramType)), "Could not retrieve module configuration for diagram type: " + diagramType); - Module clientIdModule = new ClientIdModule(clientSessionId); + Module clientIdModule = new ClientSessionModule(clientSessionId, params.getClientActionKinds()); Module diagramScopeModule = new DiagramGlobalScopeModule(diagramGlobalScope); Module clientSessionModule = ModuleUtil.mixin(diagramModule, clientIdModule, diagramScopeModule); diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/session/DefaultClientSessionManager.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/session/DefaultClientSessionManager.java index 97b98a90..56ecc065 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/session/DefaultClientSessionManager.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/internal/session/DefaultClientSessionManager.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 @@ -26,6 +26,7 @@ import org.eclipse.glsp.server.disposable.Disposable; import org.eclipse.glsp.server.protocol.GLSPServer; import org.eclipse.glsp.server.protocol.GLSPServerListener; +import org.eclipse.glsp.server.protocol.InitializeClientSessionParameters; import org.eclipse.glsp.server.session.ClientSession; import org.eclipse.glsp.server.session.ClientSessionFactory; import org.eclipse.glsp.server.session.ClientSessionListener; @@ -49,8 +50,9 @@ public DefaultClientSessionManager(final GLSPServer server) { } @Override - public synchronized ClientSession getOrCreateClientSession(final String clientSessionId, - final String diagramType) { + public synchronized ClientSession getOrCreateClientSession(final InitializeClientSessionParameters params) { + String clientSessionId = params.getClientSessionId(); + String diagramType = params.getDiagramType(); ClientSession session = clientSessions.get(clientSessionId); if (session != null) { if (!session.getDiagramType().equals(diagramType)) { @@ -62,7 +64,7 @@ public synchronized ClientSession getOrCreateClientSession(final String clientSe return session; } - ClientSession newSession = sessionFactory.create(clientSessionId, diagramType); + ClientSession newSession = sessionFactory.create(params); clientSessions.put(clientSessionId, newSession); getListenersToNotifiy(newSession).forEach(listener -> listener.sessionCreated(newSession)); return newSession; diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/protocol/DefaultGLSPServer.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/protocol/DefaultGLSPServer.java index 5903d988..9c96df3e 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/protocol/DefaultGLSPServer.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/protocol/DefaultGLSPServer.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 @@ -26,6 +26,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.eclipse.glsp.server.actions.Action; import org.eclipse.glsp.server.actions.ActionMessage; import org.eclipse.glsp.server.actions.ActionRegistry; import org.eclipse.glsp.server.session.ClientSession; @@ -81,7 +82,7 @@ public CompletableFuture initialize(final InitializeParameters this.applicationId = params.getApplicationId(); InitializeResult result = new InitializeResult(PROTOCOL_VERSION); - actionRegistry.getServerHandledActions() + actionRegistry.getHandledActionKinds() .forEach((diagramType, serverHandledActions) -> result.addServerActions(diagramType, serverHandledActions)); initialized = handleIntializeArgs(result, params.getArgs()); @@ -103,6 +104,7 @@ protected CompletableFuture handleIntializeArgs(final Initiali return CompletableFuture.completedFuture(result); } + @SuppressWarnings("deprecation") protected void validateServerInitialized() { if (!isInitialized()) { throw new ResponseErrorException(new ResponseError(ResponseErrorCode.serverNotInitialized, @@ -117,8 +119,7 @@ public CompletableFuture initializeClientSession(final InitializeClientSes validateServerInitialized(); try { - ClientSession session = sessionManager.getOrCreateClientSession(params.getClientSessionId(), - params.getDiagramType()); + ClientSession session = sessionManager.getOrCreateClientSession(params); clientSessions.put(params.getClientSessionId(), session); return handleInitializeClientSessionArgs(params.getArgs()); } catch (GLSPServerException exception) { @@ -174,7 +175,9 @@ public void process(final ActionMessage message) { }; try { - clientSessions.get(clientSessionId).getActionDispatcher().dispatch(message.getAction()) + Action action = message.getAction(); + action.setReceivedFromClient(true); + clientSessions.get(clientSessionId).getActionDispatcher().dispatch(action) .exceptionally(errorHandler); } catch (RuntimeException e) { errorHandler.apply(e); diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/protocol/InitializeClientSessionParameters.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/protocol/InitializeClientSessionParameters.java index 33cf4613..4fdb26b4 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/protocol/InitializeClientSessionParameters.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/protocol/InitializeClientSessionParameters.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2021 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 @@ -15,9 +15,10 @@ ********************************************************************************/ package org.eclipse.glsp.server.protocol; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.stream.Collectors; /** * POJO providing all arguments required for a @@ -35,6 +36,12 @@ public class InitializeClientSessionParameters { */ private String diagramType; + /* + * The set of action kinds that can be handled by the client. + * Used by the server to know which dispatched actions should be forwarded to the client. + */ + private List clientActionKinds; + /** * Additional custom arguments. */ @@ -42,6 +49,22 @@ public class InitializeClientSessionParameters { public InitializeClientSessionParameters() { this.args = new HashMap<>(); + this.clientActionKinds = new ArrayList<>(); + } + + public InitializeClientSessionParameters(final String clientSessionId, final String diagramType, + final List clientActionKinds) { + this(); + this.clientSessionId = clientSessionId; + this.diagramType = diagramType; + this.clientActionKinds = clientActionKinds; + } + + public InitializeClientSessionParameters(final String clientSessionId, final String diagramType, + final List clientActionKinds, + final Map args) { + this(clientSessionId, diagramType, clientActionKinds); + this.args = args; } public String getClientSessionId() { return clientSessionId; } @@ -56,12 +79,16 @@ public InitializeClientSessionParameters() { public void setArgs(final Map args) { this.args = args; } + public List getClientActionKinds() { return clientActionKinds; } + + public void setClientActionKinds(final List clientActionKinds) { + this.clientActionKinds = clientActionKinds; + } + @Override public String toString() { - String argsString = args.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()) - .collect(Collectors.joining(";")); return "InitializeClientSessionParameters [clientSessionId=" + clientSessionId + ", diagramType=" + diagramType - + ", args={ " + argsString + " } ]"; + + ", clientActionKinds=" + clientActionKinds + ", args=" + args + "]"; } } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/session/ClientSessionFactory.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/session/ClientSessionFactory.java index 92e1657d..8229e5eb 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/session/ClientSessionFactory.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/session/ClientSessionFactory.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2021 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 @@ -16,6 +16,7 @@ package org.eclipse.glsp.server.session; import org.eclipse.glsp.server.actions.ActionDispatcher; +import org.eclipse.glsp.server.protocol.InitializeClientSessionParameters; /** * Handles the construction of new {@link ClientSession}. A client session factory has to know @@ -25,11 +26,10 @@ public interface ClientSessionFactory { /** - * Create a new {@link ClientSession} based on the given client session id and diagram type. + * Create a new {@link ClientSession} based on the given initalize parameters. * - * @param clientSessionId The client session id. - * @param diagramType The diagram type. + * @param params The client session initialize parameters. * @return A new instance of {@link ClientSession} that correlates to the given input parameters. */ - ClientSession create(String clientSessionId, String diagramType); + ClientSession create(InitializeClientSessionParameters params); } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/session/ClientSessionManager.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/session/ClientSessionManager.java index 68b93fe9..6e585469 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/session/ClientSessionManager.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/session/ClientSessionManager.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 @@ -19,6 +19,7 @@ import java.util.Optional; import org.eclipse.glsp.server.disposable.IDisposable; +import org.eclipse.glsp.server.protocol.InitializeClientSessionParameters; import org.eclipse.glsp.server.types.GLSPServerException; /** @@ -27,17 +28,15 @@ public interface ClientSessionManager extends IDisposable { /** - * Retries an existing (or created a new) {@link ClientSession} for the given id and diagram type. + * Retries an existing (or creates a new) {@link ClientSession} for the given initalize parameters. * If a new session has been created all {@link ClientSessionListener}s are notified via the * {@link ClientSessionListener#sessionCreated(ClientSession)} method. * - * @param clientSessionId The client session id (i.e. clientId). - * @param diagramType The diagram type. - * @return The existing or newly constructed {@link ClientSession}. + * @param parms The initialize parameters * * @throws GLSPServerException if another session with matching client id but different diagram type already exists. */ - ClientSession getOrCreateClientSession(String clientSessionId, String diagramType); + ClientSession getOrCreateClientSession(InitializeClientSessionParameters params); /** * Retrieve an existing (i.e. currently active) {@link ClientSession} for the given client session id. diff --git a/tests/org.eclipse.glsp.server.test/src/org/eclipse/glsp/server/features/sourcemodelwatcher/FileWatcherTest.java b/tests/org.eclipse.glsp.server.test/src/org/eclipse/glsp/server/features/sourcemodelwatcher/FileWatcherTest.java index 95de22b4..38a57159 100644 --- a/tests/org.eclipse.glsp.server.test/src/org/eclipse/glsp/server/features/sourcemodelwatcher/FileWatcherTest.java +++ b/tests/org.eclipse.glsp.server.test/src/org/eclipse/glsp/server/features/sourcemodelwatcher/FileWatcherTest.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 @@ -38,6 +38,7 @@ import org.eclipse.glsp.server.disposable.Disposable; import org.eclipse.glsp.server.model.DefaultGModelState; import org.eclipse.glsp.server.model.GModelState; +import org.eclipse.glsp.server.protocol.InitializeClientSessionParameters; import org.eclipse.glsp.server.session.ClientSession; import org.eclipse.glsp.server.session.ClientSessionListener; import org.eclipse.glsp.server.session.ClientSessionManager; @@ -215,7 +216,7 @@ public void dispose() {} public boolean isDisposed() { return false; } @Override - public ClientSession getOrCreateClientSession(final String clientSessionId, final String diagramType) { + public ClientSession getOrCreateClientSession(final InitializeClientSessionParameters params) { return null; }