Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended workflow example by injecting non-default state #229

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ Require-Bundle: org.eclipse.glsp.layout;bundle-version="[2.0.0,3.0.0)",
org.eclipse.glsp.server.websocket;bundle-version="[2.0.0,3.0.0)",
org.eclipse.elk.core;bundle-version="0.8.1",
org.eclipse.elk.alg.layered;bundle-version="0.8.1",
org.eclipse.elk.graph;bundle-version="0.8.1"
org.eclipse.elk.graph;bundle-version="0.8.1",
com.google.gson;bundle-version="2.8.7"
Import-Package: org.apache.logging.log4j;version="2.17.1"
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.eclipse.glsp.server.features.contextactions.ContextActionsProvider;
import org.eclipse.glsp.server.features.contextactions.RequestContextActionsHandler;
import org.eclipse.glsp.server.features.contextmenu.ContextMenuItemProvider;
import org.eclipse.glsp.server.features.core.model.GModelFactory;
import org.eclipse.glsp.server.features.core.model.SourceModelStorage;
import org.eclipse.glsp.server.features.directediting.ContextEditValidator;
import org.eclipse.glsp.server.features.directediting.LabelEditValidator;
Expand All @@ -58,8 +59,8 @@
import org.eclipse.glsp.server.features.typehints.EdgeCreationChecker;
import org.eclipse.glsp.server.features.validation.ModelValidator;
import org.eclipse.glsp.server.gmodel.GModelDiagramModule;
import org.eclipse.glsp.server.gmodel.GModelStorage;
import org.eclipse.glsp.server.layout.LayoutEngine;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.operations.OperationHandler;

public class WorkflowDiagramModule extends GModelDiagramModule {
Expand All @@ -71,7 +72,17 @@ protected Class<? extends DiagramConfiguration> bindDiagramConfiguration() {

@Override
protected Class<? extends SourceModelStorage> bindSourceModelStorage() {
return GModelStorage.class;
return WorkflowModelStorage.class;
}

@Override
protected Class<? extends GModelState> bindGModelState() {
return WorkflowModelState.class;
}

@Override
protected Class<? extends GModelFactory> bindGModelFactory() {
return WorkflowModelFactory.class;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/********************************************************************************
* 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
* 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.example.workflow;

import com.google.inject.Inject;
import org.eclipse.glsp.graph.GModelRoot;
import org.eclipse.glsp.server.features.core.model.GModelFactory;

/**
* This class provides the method to transform a source model into a GModel, updating the {@link GModelRoot}.
*
* This is, however, only relevant in cases where the source model is not already a valid GModel.
*
* Here, this custom implementation only serves to provide an entrypoint, but for a more extensive example
* look to <a href="https://eclipse.dev/glsp/documentation/gmodel/#graphical-model-factory">
* https://eclipse.dev/glsp/documentation/gmodel/#graphical-model-factory</a>.
*/
public class WorkflowModelFactory implements GModelFactory {

@Inject
protected WorkflowModelState modelState;

/**
* Since this is an example using Workflow, which inherently already uses a GModel format, no difference
* exists between the underlying source model and `root`. Therefore all handlers directly update the
* root, making this method detrimental after first model creation.
*
* If other handlers are instead written to update `modelState.model`, then the root has to be updated
* after every change.
*/
@Override
public void createGModel() {
if (modelState.getRoot() == null) {
modelState.updateRoot(modelState.getModel());
modelState.getRoot().setRevision(-1);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/********************************************************************************
* 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
* 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.example.workflow;

import org.eclipse.glsp.graph.GGraph;
import org.eclipse.glsp.graph.GModelRoot;
import org.eclipse.glsp.server.model.DefaultGModelState;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.features.core.model.GModelFactory;

/**
* This model state serves to demonstrate how to extend or create a custom model state.
*
* While this may not be necessary when handling JSON formatted graphs that already
* correspond to a GModel (as the Workflow example does), since {@link DefaultGModelState}
* is sufficient, it nonetheless provides an adequte example for custom formats.
*/
public class WorkflowModelState extends DefaultGModelState {

/**
* The source model that needs to be transformed into a GModel and its {@link GModelRoot}.
* It is saved in the {@link GModelState} in order to later be available in the
* corresponding {@link GModelFactory}.
*
* Its type solely depends on the used source model.
*/
private GGraph model;

public GGraph getModel() {
return model;
}

public void setModel(GGraph model) {
this.model = model;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/********************************************************************************
* 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
* 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.example.workflow;

import com.google.gson.Gson;
import com.google.inject.Inject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import org.eclipse.glsp.graph.GGraph;
import org.eclipse.glsp.server.actions.SaveModelAction;
import org.eclipse.glsp.server.features.core.model.RequestModelAction;
import org.eclipse.glsp.server.features.core.model.SourceModelStorage;
import org.eclipse.glsp.server.gson.GraphGsonConfigurationFactory;
import org.eclipse.glsp.server.types.GLSPServerException;
import org.eclipse.glsp.server.utils.ClientOptionsUtil;
import org.eclipse.glsp.server.gmodel.GModelStorage;

/**
* This {@link SourceModelStorage} serves as a naive implementation similar to the default {@link GModelStorage}.
* The main difference being that the source model is not directly instantiated as GModel, which works
* in the Workflow example (since its data format is already a valid GModel), but not generally. Therefore,
* this example is more easily applicable to custom model formats.
*
* The model saved here is later on transformed in {@link WorkflowModelFactory} and has to be updated in the handlers,
* if source model and GModel are different.
*/
public class WorkflowModelStorage implements SourceModelStorage {

@Inject
protected WorkflowModelState modelState;

protected Gson gson;

@Inject
public void configureGson(final GraphGsonConfigurationFactory gsonConfigurator) {
gson = gsonConfigurator.configureGson().setPrettyPrinting().create();
}

@Override
public void loadSourceModel(final RequestModelAction action) {
final File file = ClientOptionsUtil.getSourceUriAsFile(action.getOptions()).orElseThrow();
try (Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
var model = gson.fromJson(reader, GGraph.class);
modelState.setModel(model);
modelState.setProperty(ClientOptionsUtil.SOURCE_URI, action.getOptions().get(ClientOptionsUtil.SOURCE_URI));
} catch (IOException e) {
throw new GLSPServerException("Could not load model from file: " + file.toURI().toString(), e);
}
}

@Override
public void saveSourceModel(final SaveModelAction action) {
File file = ClientOptionsUtil.getAsFile(modelState.getProperty(ClientOptionsUtil.SOURCE_URI, String.class).orElseThrow());
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
gson.toJson(modelState.getRoot(), GGraph.class, writer);
} catch (IOException e) {
throw new GLSPServerException("An error occured during save process.", e);
}
}

}