Skip to content

Commit

Permalink
[WIP] #150 #141 Rework dependency injection architecture
Browse files Browse the repository at this point in the history
#150 Rework DI architecture
No longer use one global injector per application connection. Instead use a global server injector and dedicated child injectors for each client session. This removes a couple of flaws/downside we had with the current approach. To achieve this the `GLSPModule` has been split into two separate modules. The `ServerModule` provides the bindings for base infrastructure & networking (used for creating the server injector) while `DiagramModules` provide language & session specific bindings (used for creating the session specific child injectors).

The main benefits are the following:
- Each session now uses its own `ActionDispatcher` this means action messages intended for different client sessions can now be handled in parallel. Previously they were processed one after the other essentially creating a bottleneck.
- One `GLSPServer` can now handler multiple different diagram implementations. The diagram language specific bindings are provided with a `DiagramModule`. When creating a new client session injector the corresponding `DiagramModule` is identified via the given diagram type.  This can for instance be used in UML-GLSP to provide all different diagram types (class,package,state machine etc.) with one server.
- Apart from the initial "process" method it is no longer necessary to keep track of the diagramid/client session id. Each session has its own instances of action handlers, operation handlers, model state, diagram configuration etc. and the clientId no longer needs to be passed as method argument. In addition, provider classes with the purpose of mapping a class instance to the correct digramId like `ModelStateProvider` or the `DiagramConfigurationRegistry` are now obsolete and have been removed.

Note that this PR only provides the DI architecture rework. Existing API whose functionality does not break after the rework as not been touched yet even tough there a various aspects of  the existing API that can now be simplified/improved. For instance, with the new approach the Action/Operation Handler API can be simplified. It is no longer necessary to pass the model state argument as part of the interface methods (see also #120). I have identified some major aspects of the API that can be improved (corresponding issues will be created after this PR is merged).

#141 Refactor `ClientSessionListener` API
- Extract listener methods for server connection from `ClientSessionListener` interface into own `ServerConnectionListener` interface. Server connection listeners are handled directly by the `GLSPServer`.
- It is now possible to define a set of clientIds for which a listener should be registered when adding a new `ClientSessionListener` to the 'ClientSessionManager`.
- The  `DefaultGLSPClientSessionManager` now autodisposes all `ClientSessionListeners` for the corresponding clientSesionId when a session is disposed.
-  Improved null-checks: The client session manager now checks for disposed listeners (i.e. null values in the map) and removes them before notifying (i.e invoking a listener method) them.

Miscellaneous
- Reduce public API exposure. Interface implementations that typically are not expected to be customized by implementing projects haven been moved to the `internal` API.
- Improve documentation. Add javadoc for all newly added interfaces and relevant public classes. Also improve documentation of some existing components.
- Merge `GLSPServerStatusAction` and `ServerStatusAction`
- Introduced 'ModuleUtil' class with provides the functionality to mixin modules similar to how it is done in Xtext.
- Remove uncessary  `.gitkeep` file.
- Rename `DefaultGLSPServerLauncher` to `SocketGLSPServerLauncher`
- Rename `ClientOptions` to `ClientOptionsUtil` to conform to the standard naming scheme for util classes
  • Loading branch information
tortmayr committed Sep 4, 2021
1 parent 9e7202e commit 43795fc
Show file tree
Hide file tree
Showing 111 changed files with 2,142 additions and 1,277 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2019 EclipseSource and others.
* Copyright (c) 2019-2021 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
Expand Down Expand Up @@ -40,15 +40,12 @@
import org.eclipse.glsp.example.workflow.wfgraph.WfgraphPackage;
import org.eclipse.glsp.graph.DefaultTypes;
import org.eclipse.glsp.graph.GraphPackage;
import org.eclipse.glsp.server.diagram.DiagramConfiguration;
import org.eclipse.glsp.server.diagram.EdgeTypeHint;
import org.eclipse.glsp.server.diagram.ShapeTypeHint;
import org.eclipse.glsp.server.diagram.BaseDiagramConfiguration;
import org.eclipse.glsp.server.layout.ServerLayoutKind;
import org.eclipse.glsp.server.types.EdgeTypeHint;
import org.eclipse.glsp.server.types.ShapeTypeHint;

public class WorkflowDiagramConfiguration implements DiagramConfiguration {

@Override
public String getDiagramType() { return "workflow-diagram"; }
public class WorkflowDiagramConfiguration extends BaseDiagramConfiguration {

@Override
public Map<String, EClass> getTypeMappings() {
Expand Down Expand Up @@ -80,7 +77,7 @@ public List<ShapeTypeHint> getShapeTypeHints() {
public List<EdgeTypeHint> getEdgeTypeHints() {
List<EdgeTypeHint> edgeHints = new ArrayList<>();
edgeHints.add(createDefaultEdgeTypeHint(EDGE));
EdgeTypeHint weightedEdgeHint = DiagramConfiguration.super.createDefaultEdgeTypeHint(WEIGHTED_EDGE);
EdgeTypeHint weightedEdgeHint = super.createDefaultEdgeTypeHint(WEIGHTED_EDGE);
weightedEdgeHint.setSourceElementTypeIds(Arrays.asList(DECISION_NODE));
weightedEdgeHint.setTargetElementTypeIds(Arrays.asList(MANUAL_TASK, AUTOMATED_TASK, FORK_NODE, JOIN_NODE));
edgeHints.add(weightedEdgeHint);
Expand All @@ -89,7 +86,7 @@ public List<EdgeTypeHint> getEdgeTypeHints() {

@Override
public EdgeTypeHint createDefaultEdgeTypeHint(final String elementId) {
EdgeTypeHint hint = DiagramConfiguration.super.createDefaultEdgeTypeHint(elementId);
EdgeTypeHint hint = super.createDefaultEdgeTypeHint(elementId);
hint.setSourceElementTypeIds(
Arrays.asList(MANUAL_TASK, AUTOMATED_TASK, DECISION_NODE, MERGE_NODE, FORK_NODE, JOIN_NODE));
hint.setTargetElementTypeIds(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2019-2020 EclipseSource and others.
* Copyright (c) 2019-2021 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
Expand Down Expand Up @@ -40,7 +40,8 @@
import org.eclipse.glsp.example.workflow.taskedit.TaskEditValidator;
import org.eclipse.glsp.graph.GraphExtension;
import org.eclipse.glsp.server.actions.ActionHandler;
import org.eclipse.glsp.server.di.DefaultGLSPModule;
import org.eclipse.glsp.server.di.GModelJsonDiagramModule;
import org.eclipse.glsp.server.di.MultiBinding;
import org.eclipse.glsp.server.diagram.DiagramConfiguration;
import org.eclipse.glsp.server.features.commandpalette.CommandPaletteActionProvider;
import org.eclipse.glsp.server.features.contextactions.ContextActionsProvider;
Expand All @@ -57,16 +58,15 @@
import org.eclipse.glsp.server.features.navigation.NavigationTargetResolver;
import org.eclipse.glsp.server.features.popup.PopupModelFactory;
import org.eclipse.glsp.server.features.validation.ModelValidator;
import org.eclipse.glsp.server.layout.ILayoutEngine;
import org.eclipse.glsp.server.internal.di.MultiBindingDefaults;
import org.eclipse.glsp.server.layout.LayoutEngine;
import org.eclipse.glsp.server.operations.OperationHandler;
import org.eclipse.glsp.server.protocol.GLSPServer;
import org.eclipse.glsp.server.utils.MultiBinding;

public class WorkflowGLSPModule extends DefaultGLSPModule {
public class WorkflowDiagramModule extends GModelJsonDiagramModule {

@Override
protected Class<? extends GLSPServer> bindGLSPServer() {
return WorkflowGLSPServer.class;
protected Class<? extends DiagramConfiguration> bindDiagramConfiguration() {
return WorkflowDiagramConfiguration.class;
}

@Override
Expand Down Expand Up @@ -101,11 +101,6 @@ protected void configureContextEditValidators(final MultiBinding<ContextEditVali
binding.add(TaskEditValidator.class);
}

@Override
protected void configureDiagramConfigurations(final MultiBinding<DiagramConfiguration> binding) {
binding.add(WorkflowDiagramConfiguration.class);
}

@Override
protected void configureNavigationTargetProviders(final MultiBinding<NavigationTargetProvider> binding) {
super.configureNavigationTargetProviders(binding);
Expand All @@ -114,9 +109,11 @@ protected void configureNavigationTargetProviders(final MultiBinding<NavigationT
binding.add(NodeDocumentationNavigationTargetProvider.class);
}

@SuppressWarnings("restriction")
@Override
protected void configureOperationHandlers(final MultiBinding<OperationHandler> binding) {
super.configureOperationHandlers(binding);
binding.addAll(MultiBindingDefaults.DEFAULT_OPERATION_HANDLERS);
binding.add(CreateAutomatedTaskHandler.class);
binding.add(CreateManualTaskHandler.class);
binding.add(CreateDecisionNodeHandler.class);
Expand Down Expand Up @@ -152,7 +149,7 @@ protected Class<? extends LabelEditValidator> bindLabelEditValidator() {
}

@Override
protected Class<? extends ILayoutEngine> bindLayoutEngine() {
protected Class<? extends LayoutEngine> bindLayoutEngine() {
return WorkflowLayoutEngine.class;
}

Expand All @@ -171,4 +168,7 @@ protected Class<? extends NavigationTargetResolver> bindNavigationTargetResolver
return WorkflowNavigationTargetResolver.class;
}

@Override
public String getDiagramType() { return "workflow-diagram"; }

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
********************************************************************************/
package org.eclipse.glsp.example.workflow;

import static org.eclipse.glsp.server.protocol.GLSPServerException.getOrThrow;
import static org.eclipse.glsp.server.types.GLSPServerException.getOrThrow;

import java.util.Map;
import java.util.concurrent.CompletableFuture;

import org.apache.log4j.Logger;
import org.eclipse.glsp.server.jsonrpc.DefaultGLSPServer;
import org.eclipse.glsp.server.protocol.DefaultGLSPServer;
import org.eclipse.glsp.server.protocol.InitializeResult;
import org.eclipse.glsp.server.utils.MapUtil;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2019 EclipseSource and others.
* Copyright (c) 2019-2021 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
Expand All @@ -19,9 +19,10 @@

import org.apache.commons.cli.ParseException;
import org.eclipse.elk.alg.layered.options.LayeredMetaDataProvider;
import org.eclipse.glsp.example.workflow.WorkflowGLSPModule;
import org.eclipse.glsp.example.workflow.WorkflowDiagramModule;
import org.eclipse.glsp.layout.ElkLayoutEngine;
import org.eclipse.glsp.server.launch.DefaultGLSPServerLauncher;
import org.eclipse.glsp.server.di.ServerModule;
import org.eclipse.glsp.server.launch.SocketGLSPServerLauncher;
import org.eclipse.glsp.server.launch.GLSPServerLauncher;
import org.eclipse.glsp.server.utils.LaunchUtil;
import org.eclipse.glsp.server.websocket.WebsocketServerLauncher;
Expand All @@ -38,10 +39,12 @@ public static void main(final String[] args) {
ElkLayoutEngine.initialize(new LayeredMetaDataProvider());

int port = parser.parsePort();
ServerModule workflowServerModule = new ServerModule()
.configureDiagramModule(new WorkflowDiagramModule());

GLSPServerLauncher launcher = parser.isWebsocket()
? new WebsocketServerLauncher(new WorkflowGLSPModule(), "/workflow")
: new DefaultGLSPServerLauncher(new WorkflowGLSPModule());
? new WebsocketServerLauncher(workflowServerModule, "/workflow")
: new SocketGLSPServerLauncher(workflowServerModule);

launcher.start("localhost", port);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@
import org.eclipse.glsp.server.features.navigation.NavigationTargetProvider;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.types.EditorContext;
import org.eclipse.glsp.server.utils.ClientOptions;
import org.eclipse.glsp.server.utils.ClientOptionsUtil;
import org.eclipse.glsp.server.utils.MapUtil;

public abstract class AbstractNextOrPreviousNavigationTargetProvider implements NavigationTargetProvider {

@Override
public List<? extends NavigationTarget> getTargets(final EditorContext editorContext,
final GModelState modelState) {
Optional<String> sourceUri = MapUtil.getValue(modelState.getClientOptions(), ClientOptions.SOURCE_URI);
Optional<String> sourceUri = MapUtil.getValue(modelState.getClientOptions(), ClientOptionsUtil.SOURCE_URI);
return editorContext.getSelectedElementIds().stream()
.flatMap(id -> modelState.getIndex().get(id).stream())
.filter(TaskNode.class::isInstance).map(TaskNode.class::cast)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import org.eclipse.glsp.server.features.navigation.NavigationTargetProvider;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.types.EditorContext;
import org.eclipse.glsp.server.utils.ClientOptions;
import org.eclipse.glsp.server.utils.ClientOptionsUtil;
import org.eclipse.glsp.server.utils.MapUtil;

/**
Expand All @@ -50,7 +50,7 @@ public List<? extends NavigationTarget> getTargets(final EditorContext editorCon
return Arrays.asList();
}

Optional<String> sourceUri = MapUtil.getValue(modelState.getClientOptions(), ClientOptions.SOURCE_URI);
Optional<String> sourceUri = MapUtil.getValue(modelState.getClientOptions(), ClientOptionsUtil.SOURCE_URI);
if (sourceUri.isEmpty()) {
return Arrays.asList();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2020 EclipseSource and others.
* Copyright (c) 2020-2021 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
Expand All @@ -18,7 +18,7 @@
import org.eclipse.glsp.server.actions.ActionDispatcher;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.operations.BasicOperationHandler;
import org.eclipse.glsp.server.protocol.GLSPServerException;
import org.eclipse.glsp.server.types.GLSPServerException;

import com.google.inject.Inject;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2020 EclipseSource and others.
* Copyright (c) 2020-2021 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
Expand All @@ -20,7 +20,7 @@
import org.eclipse.glsp.example.workflow.wfgraph.TaskNode;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.operations.BasicOperationHandler;
import org.eclipse.glsp.server.protocol.GLSPServerException;
import org.eclipse.glsp.server.types.GLSPServerException;

public class EditTaskOperationHandler extends BasicOperationHandler<EditTaskOperation> {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2019 EclipseSource and others.
* Copyright (c) 2019-2021 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
Expand Down Expand Up @@ -40,18 +40,18 @@

import com.google.gson.GsonBuilder;

public class GGraphGsonConfigurator {
public class GraphGsonConfigurator {

public static final String DEFAULT_TYPE_ATT = "type";

private final Map<String, EClass> typeMap = new HashMap<>();
private final List<EPackage> ePackages = new ArrayList<>();

public GGraphGsonConfigurator() {
public GraphGsonConfigurator() {
withEPackages(GraphPackage.eINSTANCE);
}

public GGraphGsonConfigurator withDefaultTypes() {
public GraphGsonConfigurator withDefaultTypes() {
Map<String, EClass> defaultTypes = new HashMap<>();
defaultTypes.put(GRAPH, GGRAPH);
defaultTypes.put(NODE, GNODE);
Expand All @@ -61,12 +61,12 @@ public GGraphGsonConfigurator withDefaultTypes() {
return withTypes(defaultTypes);
}

public GGraphGsonConfigurator withTypes(final Map<String, EClass> types) {
public GraphGsonConfigurator withTypes(final Map<String, EClass> types) {
typeMap.putAll(types);
return this;
}

public GGraphGsonConfigurator withEPackages(final EPackage... packages) {
public GraphGsonConfigurator withEPackages(final EPackage... packages) {
ePackages.addAll(Arrays.asList(packages));
return this;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/********************************************************************************
* Copyright (c) 2018 TypeFox and others.
* (c) 2019 EclipseSource (adaptation for GModel)
* (c) 2019-2021 EclipseSource (adaptation for GModel)
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand Down Expand Up @@ -59,7 +59,7 @@
import org.eclipse.glsp.graph.GPoint;
import org.eclipse.glsp.graph.GPort;
import org.eclipse.glsp.graph.GraphFactory;
import org.eclipse.glsp.server.layout.ILayoutEngine;
import org.eclipse.glsp.server.layout.LayoutEngine;
import org.eclipse.glsp.server.model.GModelState;

import com.google.common.collect.Maps;
Expand All @@ -75,7 +75,7 @@
* algorithms that should be used by this layout engine.
* </p>
*/
public class ElkLayoutEngine implements ILayoutEngine {
public class ElkLayoutEngine implements LayoutEngine {

public static final IProperty<String> P_TYPE = new Property<>("org.eclipse.sprotty.layout.type");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019-2020 EclipseSource and others.
* Copyright (c) 2019-2021 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
Expand All @@ -21,7 +21,7 @@
import javax.websocket.EndpointConfig;
import javax.websocket.Session;

import org.eclipse.glsp.server.jsonrpc.GsonConfigurator;
import org.eclipse.glsp.server.gson.ServerGsonConfigurator;
import org.eclipse.glsp.server.protocol.GLSPClient;
import org.eclipse.glsp.server.protocol.GLSPServer;
import org.eclipse.lsp4j.jsonrpc.Launcher.Builder;
Expand All @@ -35,7 +35,7 @@ public class GLSPServerEndpoint extends WebSocketEndpoint<GLSPClient> {
private GLSPServer glspServer;

@Inject
private GsonConfigurator gsonConfigurator;
private ServerGsonConfigurator gsonConfigurator;

@Override
protected void configure(final Builder<GLSPClient> builder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019 EclipseSource and others.
* Copyright (c) 2019-2021 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
Expand All @@ -22,28 +22,26 @@
import javax.websocket.server.ServerEndpointConfig;

import org.apache.log4j.Logger;
import org.eclipse.glsp.server.di.GLSPModule;
import org.eclipse.glsp.server.di.ServerModule;
import org.eclipse.glsp.server.launch.GLSPServerLauncher;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;

import com.google.inject.Module;

public class WebsocketServerLauncher extends GLSPServerLauncher {
private static Logger LOG = Logger.getLogger(WebsocketServerLauncher.class);
private Server server;
private String clientAppPath;
private final String endpointPath;

public WebsocketServerLauncher(final GLSPModule module, final String endpointPath) {
super(module);
public WebsocketServerLauncher(final ServerModule serverModule, final String endpointPath,
final Module... additionalModules) {
super(serverModule, additionalModules);
this.endpointPath = endpointPath.startsWith("/") ? endpointPath.substring(1) : endpointPath;
addAdditionalModules(new WebsocketModule());
}

public WebsocketServerLauncher(final GLSPModule module, final String endpointPath, final String clientAppPath) {
this(module, endpointPath);
this.clientAppPath = clientAppPath;
}

@Override
Expand Down
Loading

0 comments on commit 43795fc

Please sign in to comment.