Skip to content
This repository has been archived by the owner on Jan 15, 2020. It is now read-only.

Extend GLSP Protocol with "initialize" method #302

Merged
merged 2 commits into from
Jul 17, 2019
Merged
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 @@ -18,9 +18,21 @@ import { injectable } from "inversify";

import { WorkflowLanguage } from "../../common/workflow-language";

export interface WorkflowInitializeOptions {
timestamp: Date,
message: string
}

@injectable()
export class WorkflowGLSPClientContribution extends BaseGLSPClientContribution {
readonly id = WorkflowLanguage.Id;
readonly name = WorkflowLanguage.Name;
readonly fileExtensions = [WorkflowLanguage.FileExtension];

protected createInitializeOptions(): WorkflowInitializeOptions {
return {
timestamp: new Date(),
message: "Custom Options Available"
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { inject, injectable, multiInject } from "inversify";
import { DiagramManagerProvider } from "sprotty-theia/lib";
import { MessageConnection, ResponseError } from "vscode-jsonrpc";

import { InitializeParameters } from "../../common";
import { GLSPClientFactory } from "./glsp-client";
import { GLSPClient, GLSPClientOptions } from "./glsp-client-services";

Expand Down Expand Up @@ -105,16 +106,44 @@ export abstract class BaseGLSPClientContribution implements GLSPClientContributi
}));
}
protected readonly toDeactivate = new DisposableCollection();

activate(): Disposable {
if (this.toDeactivate.disposed) {
this.doActivate(this.toDeactivate);
this.doActivate(this.toDeactivate)
.then(() => this.initialize());
}
return this.toDeactivate;
}

deactivate(): void {
this.toDeactivate.dispose();
}

protected createInitializeParameters(): InitializeParameters {
const initOptions = this.createInitializeOptions();
return initOptions ? { options: initOptions } : {};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: This could be simplified by reusing the interface key name for the const:

const options = this.createInitializeOptions();
return { options };

}

protected createInitializeOptions(): any {
return undefined;
}

initialize(): void {
const parameters = this.createInitializeParameters();
this.glspClient.then(client => client.initialize(parameters)
.then(success => {
if (!success) {
this.messageService.error(`Failed to initialize ${this.name} glsp server with ${JSON.stringify(parameters)}`, 'Retry')
.then(retry => {
if (retry) {
this.initialize();
}
});
}
})
);
}

protected async doActivate(toDeactivate: DisposableCollection): Promise<void> {
const options: WebSocketOptions = {};
toDeactivate.push(Disposable.create(() => options.reconnecting = false));
Expand Down Expand Up @@ -174,7 +203,6 @@ export abstract class BaseGLSPClientContribution implements GLSPClientContributi
protected createOptions(): GLSPClientOptions {
return {
initializationFailedHandler: err => this.handleInitializationFailed(err),

};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ import {
} from "@theia/languages/lib/browser";
import { Disposable, Message, MessageConnection, NotificationHandler, NotificationType } from "vscode-jsonrpc";

import { ExitNotification, ShutdownRequest } from "../../common";
import { ExitNotification, InitializeParameters, InitializeRequest, ShutdownRequest } from "../../common";


export const GLSPClient = Symbol.for('GLSPClient');

export interface GLSPClient {
onReady(): Promise<void>
start(): Disposable;
initialize(params: InitializeParameters): Thenable<Boolean>;
stop(): Thenable<void> | undefined
onNotification<P, RO>(type: NotificationType<P, RO>, handler: NotificationHandler<P>): void;
sendNotification<P, RO>(type: NotificationType<P, RO>, params?: P): void;
Expand All @@ -57,6 +58,7 @@ export interface Connection {
listen(): void
onNotification<P, RO>(type: NotificationType<P, RO>, handler: NotificationHandler<P>): void;
sendNotification<P, RO>(type: NotificationType<P, RO>, params?: P): void;
initialize(params: InitializeParameters): Thenable<Boolean>;
shutdown(): Thenable<void>;
exit(): void;
dispose(): void;
Expand All @@ -76,6 +78,7 @@ export function createConnection(connection: MessageConnection, errorHandler: Co
listen: () => connection.listen(),
sendNotification: <P, RO>(type: NotificationType<P, RO>, params?: P): void => connection.sendNotification(type, params),
onNotification: <P, RO>(type: NotificationType<P, RO>, handler: NotificationHandler<P>): void => connection.onNotification(type, handler),
initialize: (params: InitializeParameters) => connection.sendRequest(InitializeRequest.type, params),
shutdown: () => connection.sendRequest(ShutdownRequest.type, undefined),
exit: () => connection.sendNotification(ExitNotification.type),
dispose: () => connection.dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { LanguageContribution } from "@theia/languages/lib/common";
import { inject, injectable } from "inversify";
import { MessageConnection, NotificationType } from "vscode-jsonrpc";

import { InitializeParameters } from "../../common";
import { Connection, ConnectionProvider, createConnection, GLSPClient, GLSPClientOptions } from "./glsp-client-services";

enum ClientState {
Expand Down Expand Up @@ -53,6 +54,7 @@ export class BaseGLSPClient implements GLSPClient {
this.state = ClientState.Initial;

}

start(): Disposable {
this.state = ClientState.Starting;
this.resolveConnection().then((connection) => {
Expand All @@ -68,6 +70,13 @@ export class BaseGLSPClient implements GLSPClient {

}

initialize(params: InitializeParameters): Thenable<Boolean> {
if (this.connectionPromise && this.resolvedConnection) {
return this.resolvedConnection.initialize(params);
}
return Promise.resolve(false);
}

public stop(): Thenable<void> | undefined {
if (!this.connectionPromise) {
this.state = ClientState.Stopped;
Expand Down
11 changes: 10 additions & 1 deletion client/packages/theia-integration/src/common/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,21 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import { ActionMessage } from "@glsp/sprotty-client/lib";
import { NotificationType, NotificationType0, RequestType0 } from "vscode-jsonrpc";
import { NotificationType, NotificationType0, RequestType, RequestType0 } from "vscode-jsonrpc";


export interface InitializeParameters {
options?: any
}

export namespace ActionMessageNotification {
export const type = new NotificationType<ActionMessage, void>('process');
}

export namespace InitializeRequest {
export const type = new RequestType<InitializeParameters, Boolean, void, void>('initialize');
}

export namespace ShutdownRequest {
export const type = new RequestType0<void, void, void>('shutdown');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.eclipsesource.glsp.api.factory.PopupModelFactory;
import com.eclipsesource.glsp.api.handler.OperationHandler;
import com.eclipsesource.glsp.api.handler.ServerCommandHandler;
import com.eclipsesource.glsp.api.jsonrpc.GLSPServer;
import com.eclipsesource.glsp.api.labeledit.LabelEditValidator;
import com.eclipsesource.glsp.api.layout.ILayoutEngine;
import com.eclipsesource.glsp.api.markers.ModelValidator;
Expand All @@ -46,13 +47,19 @@
import com.eclipsesource.glsp.example.workflow.marker.WorkflowModelValidator;
import com.eclipsesource.glsp.graph.GraphExtension;
import com.eclipsesource.glsp.server.di.DefaultGLSPModule;
import com.eclipsesource.glsp.server.jsonrpc.DefaultGLSPServer;
import com.eclipsesource.glsp.server.operationhandler.ApplyLabelEditOperationHandler;
import com.eclipsesource.glsp.server.operationhandler.ChangeBoundsOperationHandler;
import com.eclipsesource.glsp.server.operationhandler.DeleteOperationHandler;

@SuppressWarnings("serial")
public class WorkflowGLSPModule extends DefaultGLSPModule {

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

@Override
public Class<? extends PopupModelFactory> bindPopupModelFactory() {
return WorkflowPopupFactory.class;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2019 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
* http://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 com.eclipsesource.glsp.example.workflow;

import java.util.concurrent.CompletableFuture;

import org.apache.log4j.Logger;

import com.eclipsesource.glsp.server.jsonrpc.DefaultGLSPServer;

public class WorkflowGLSPServer extends DefaultGLSPServer<WorkflowInitializeOptions> {
static Logger log = Logger.getLogger(WorkflowGLSPServer.class);

public WorkflowGLSPServer() {
super(WorkflowInitializeOptions.class);
}

@Override
public CompletableFuture<Boolean> handleOptions(WorkflowInitializeOptions options) {
if(options != null) {
log.debug(options.getTimestamp() + ": " + options.getMessage());
}
return CompletableFuture.completedFuture(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2019 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
* http://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 com.eclipsesource.glsp.example.workflow;

import java.util.Date;

public class WorkflowInitializeOptions {
private Date timestamp;
private String message;

public Date getTimestamp() {
return timestamp;
}

public String getMessage() {
return message;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public interface Provider {
GLSPServer getGraphicalLanguageServer(String clientId);
}

void initialize();
@JsonRequest("initialize")
CompletableFuture<Boolean> initialize(InitializeParameters params);

@JsonNotification("process")
void process(ActionMessage message);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2019 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
* http://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 com.eclipsesource.glsp.api.jsonrpc;

import org.eclipse.lsp4j.jsonrpc.json.adapters.JsonElementTypeAdapter;

import com.google.gson.annotations.JsonAdapter;

public class InitializeParameters {
@JsonAdapter(JsonElementTypeAdapter.Factory.class)
private Object options;

public Object getOptions() {
return options;
}

public void setOptions(Object options) {
this.options = options;
}

@Override
public String toString() {
return "InitializeParameters[options = " + options + "]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@
import com.eclipsesource.glsp.api.action.kind.IdentifiableResponseAction;
import com.eclipsesource.glsp.api.jsonrpc.GLSPClient;
import com.eclipsesource.glsp.api.jsonrpc.GLSPServer;
import com.eclipsesource.glsp.api.jsonrpc.InitializeParameters;
import com.eclipsesource.glsp.api.model.ModelStateProvider;
import com.eclipsesource.glsp.api.types.ServerStatus;
import com.eclipsesource.glsp.api.types.ServerStatus.Severity;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.inject.Inject;

public class DefaultGLSPServer implements GLSPServer {
public class DefaultGLSPServer<T> implements GLSPServer {

@Inject
private ModelStateProvider modelStateProvider;
Expand All @@ -43,12 +46,32 @@ public class DefaultGLSPServer implements GLSPServer {
private ServerStatus status;

private GLSPClient clientProxy;
private Class<T> optionsClazz;

public DefaultGLSPServer() {
this(null);
}

public DefaultGLSPServer(Class<T> optionsClazz) {
this.optionsClazz = optionsClazz;
}

@Override
public void initialize() {
public CompletableFuture<Boolean> initialize(InitializeParameters params) {
try {
if(optionsClazz != null && params.getOptions() instanceof JsonElement) {
T options = new Gson().fromJson((JsonElement)params.getOptions(), optionsClazz);
return handleOptions(options);
}
return handleOptions(null);
} catch(Throwable ex) {
log.error("Could not initialize server due to corrupted options: " + params.getOptions(), ex);
return CompletableFuture.completedFuture(false);
}
}

protected CompletableFuture<Boolean> handleOptions(T options) {
return CompletableFuture.completedFuture(true);
}

@Override
Expand Down