Skip to content

Commit

Permalink
#1794 implement 'ShowMessageRequest'
Browse files Browse the repository at this point in the history
Signed-off-by: Yevhen Vydolob <evidolob@codenvy.com>
  • Loading branch information
Yevhen Vydolob committed Jul 20, 2017
1 parent 3c2aa13 commit a8d3206
Show file tree
Hide file tree
Showing 20 changed files with 778 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ public class JsonRpcPromise<R> {
private BiConsumer<String, JsonRpcError> failureConsumer;
private Runnable timeoutRunnable;

Optional<BiConsumer<String, R>> getSuccessConsumer() {
public Optional<BiConsumer<String, R>> getSuccessConsumer() {
return Optional.ofNullable(successConsumer);
}

Optional<BiConsumer<String, JsonRpcError>> getFailureConsumer() {
public Optional<BiConsumer<String, JsonRpcError>> getFailureConsumer() {
return Optional.ofNullable(failureConsumer);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,17 @@
public class RequestHandlerManager {
private final static Logger LOGGER = getLogger(RequestHandlerManager.class);

private final Map<String, Category> methodToCategory = new ConcurrentHashMap<>();
private final Map<String, OneToOneHandler> oneToOneHandlers = new ConcurrentHashMap<>();
private final Map<String, OneToManyHandler> oneToManyHandlers = new ConcurrentHashMap<>();
private final Map<String, OneToNoneHandler> oneToNoneHandlers = new ConcurrentHashMap<>();
private final Map<String, ManyToOneHandler> manyToOneHandlers = new ConcurrentHashMap<>();
private final Map<String, ManyToManyHandler> manyToManyHandlers = new ConcurrentHashMap<>();
private final Map<String, ManyToNoneHandler> manyToNoneHandlers = new ConcurrentHashMap<>();
private final Map<String, NoneToOneHandler> noneToOneHandlers = new ConcurrentHashMap<>();
private final Map<String, NoneToManyHandler> noneToManyHandlers = new ConcurrentHashMap<>();
private final Map<String, NoneToNoneHandler> noneToNoneHandlers = new ConcurrentHashMap<>();
private final Map<String, Category> methodToCategory = new ConcurrentHashMap<>();
private final Map<String, OneToOneHandler> oneToOneHandlers = new ConcurrentHashMap<>();
private final Map<String, OneToPromiseOneHandler> oneToPromiseOneHandlers = new ConcurrentHashMap<>();
private final Map<String, OneToManyHandler> oneToManyHandlers = new ConcurrentHashMap<>();
private final Map<String, OneToNoneHandler> oneToNoneHandlers = new ConcurrentHashMap<>();
private final Map<String, ManyToOneHandler> manyToOneHandlers = new ConcurrentHashMap<>();
private final Map<String, ManyToManyHandler> manyToManyHandlers = new ConcurrentHashMap<>();
private final Map<String, ManyToNoneHandler> manyToNoneHandlers = new ConcurrentHashMap<>();
private final Map<String, NoneToOneHandler> noneToOneHandlers = new ConcurrentHashMap<>();
private final Map<String, NoneToManyHandler> noneToManyHandlers = new ConcurrentHashMap<>();
private final Map<String, NoneToNoneHandler> noneToNoneHandlers = new ConcurrentHashMap<>();

private final WebSocketMessageTransmitter transmitter;
private final JsonRpcComposer dtoComposer;
Expand All @@ -74,7 +75,15 @@ public synchronized <P, R> void registerOneToOne(String method, Class<P> pClass
oneToOneHandlers.put(method, new OneToOneHandler<>(pClass, rClass, biFunction));
}

public synchronized <P, R> void registerOneToMany(String method, Class<P> pClass, Class<R> rClass, BiFunction<String, P, List<R>> biFunction) {
public synchronized <P, R> void registerOneToPromiseOne(String method, Class<P> pClass, Class<R> rClass,
BiFunction<String, P, JsonRpcPromise<R>> function) {
mustNotBeRegistered(method);
methodToCategory.put(method, Category.ONE_TO_PROMISE_ONE);
oneToPromiseOneHandlers.put(method, new OneToPromiseOneHandler<>(pClass, rClass, function));
}

public synchronized <P, R> void registerOneToMany(String method, Class<P> pClass, Class<R> rClass,
BiFunction<String, P, List<R>> biFunction) {
mustNotBeRegistered(method);

methodToCategory.put(method, Category.ONE_TO_MANY);
Expand Down Expand Up @@ -168,6 +177,9 @@ public synchronized boolean deregister(String method) {
break;
case NONE_TO_NONE:
noneToNoneHandlers.remove(method);
break;
case ONE_TO_PROMISE_ONE:
oneToPromiseOneHandlers.remove(method);
}

return true;
Expand Down Expand Up @@ -201,6 +213,10 @@ public void handle(String endpointId, String requestId, String method, JsonRpcPa
NoneToManyHandler noneToManyHandler = noneToManyHandlers.get(method);
transmitMany(endpointId, requestId, noneToManyHandler.handle(endpointId));
break;
case ONE_TO_PROMISE_ONE:
OneToPromiseOneHandler promiseOneHandler = oneToPromiseOneHandlers.get(method);
transmitPromiseOne(endpointId, requestId, promiseOneHandler.handle(endpointId, params));
break;
default:
LOGGER.error("Something went wrong trying to find out handler category");
}
Expand Down Expand Up @@ -247,6 +263,15 @@ private void transmitOne(String endpointId, String id, Object result) {
transmitter.transmit(endpointId, message);
}

private void transmitPromiseOne(String endpointId, String requestId, JsonRpcPromise<Object> promise) {
promise.onSuccess(result -> transmitOne(endpointId, requestId, result));
promise.onFailure(jsonRpcError -> {
JsonRpcResponse jsonRpcResponse = new JsonRpcResponse(requestId, null, jsonRpcError);
String message = marshaller.marshall(jsonRpcResponse);
transmitter.transmit(endpointId, message);
});
}

private void transmitMany(String endpointId, String id, List<?> result) {
JsonRpcResult jsonRpcResult = new JsonRpcResult(result);
JsonRpcResponse jsonRpcResponse = new JsonRpcResponse(id, jsonRpcResult, null);
Expand All @@ -263,7 +288,8 @@ public enum Category {
MANY_TO_NONE,
NONE_TO_ONE,
NONE_TO_MANY,
NONE_TO_NONE
NONE_TO_NONE,
ONE_TO_PROMISE_ONE
}

private class OneToOneHandler<P, R> {
Expand All @@ -283,6 +309,23 @@ private R handle(String endpointId, JsonRpcParams params) {
}
}

private class OneToPromiseOneHandler<P, R> {
final private Class<P> pClass;
final private Class<R> rClass;
private BiFunction<String, P, JsonRpcPromise<R>> function;

private OneToPromiseOneHandler(Class<P> pClass, Class<R> rClass, BiFunction<String, P, JsonRpcPromise<R>> function) {
this.pClass = pClass;
this.rClass = rClass;
this.function = function;
}

private JsonRpcPromise<R> handle(String endpointId, JsonRpcParams params) {
P dto = dtoComposer.composeOne(params, pClass);
return function.apply(endpointId, dto);
}
}

private class OneToManyHandler<P, R> {
final private Class<P> pClass;
final private Class<R> rClass;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/

package org.eclipse.che.api.core.jsonrpc.commons.reception;

import org.eclipse.che.api.core.jsonrpc.commons.JsonRpcPromise;
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerManager;
import org.slf4j.Logger;

import java.util.function.BiFunction;
import java.util.function.Function;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;

/**
* Function configurator to define a function to be applied when we
* handle incoming JSON RPC request with params object that is
* represented by a single object while the result of a function is
* also a single object.
*
* @param <P>
* type of params object
* @param <R>
* type of result object
*/
public class PromiseConfigurationOneToOne<P, R> {
private final static Logger LOGGER = getLogger(PromiseConfigurationOneToOne.class);

private final RequestHandlerManager handlerManager;

private final String method;
private final Class<P> pClass;
private final Class<R> rClass;

PromiseConfigurationOneToOne(RequestHandlerManager handlerManager, String method, Class<P> pClass, Class<R> rClass) {
this.handlerManager = handlerManager;

this.method = method;
this.pClass = pClass;
this.rClass = rClass;
}

/**
* Define a binary function to be applied
*
* @param function
* function
*/
public void withPromiseBiFunction(BiFunction<String, P, JsonRpcPromise<R>> function) {
checkNotNull(function, "Request promise must not be null");

LOGGER.debug("Configuring incoming request binary: " +
"function for method: " + method + ", " +
"params object class: " + pClass + ", " +
"result object class: " + rClass);

handlerManager.registerOneToPromiseOne(method, pClass, rClass, function);


}


/**
* Define a function to be applied
*
* @param function
* function
*/
public void withPromise(Function<P, JsonRpcPromise<R>> function) {
withPromiseBiFunction((s, p) -> function.apply(p));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ public <R> FunctionConfiguratorOneToOne<P, R> resultAsDto(Class<R> rClass) {
return new FunctionConfiguratorOneToOne<>(requestHandlerManager, method, pClass, rClass);
}

public <R> PromiseConfigurationOneToOne<P, R> resultAsPromiseDto(Class<R> rClass) {
checkNotNull(rClass, "Result class must not be null");

LOGGER.debug("Configuring incoming request result: " +
"method: " + method + ", " +
"result object class: " + rClass);

return new PromiseConfigurationOneToOne<>(requestHandlerManager, method, pClass, rClass);
}

public FunctionConfiguratorOneToOne<P, Void> resultAsEmpty() {
LOGGER.debug("Configuring incoming request result: " +
"method: " + method + ", " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
import org.eclipse.che.plugin.languageserver.ide.editor.ShowMessageProcessor;
import org.eclipse.che.plugin.languageserver.ide.window.ShowMessageProcessor;
import org.eclipse.che.plugin.languageserver.ide.window.ShowMessageRequestProcessor;
import org.eclipse.lsp4j.MessageActionItem;
import org.eclipse.lsp4j.ShowMessageRequestParams;

/**
Expand All @@ -41,4 +43,22 @@ private void subscribe(RequestTransmitter transmitter) {
.noParams()
.sendAndSkipResult();
}

@Inject
private void configureShowMessageRequestReceiver(Provider<ShowMessageRequestProcessor> provider, RequestHandlerConfigurator configurator) {
configurator.newConfiguration()
.methodName("window/showMessageRequest")
.paramsAsDto(ShowMessageRequestParams.class)
.resultAsPromiseDto(MessageActionItem.class)
.withPromise(params -> provider.get().processNotificationRequest(params));
}

@Inject
private void subscribeShowMessageRequest(RequestTransmitter transmitter) {
transmitter.newRequest()
.endpointId("ws-agent")
.methodName("window/showMessageRequest/subscribe")
.noParams()
.sendAndSkipResult();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.languageserver.ide.editor;
package org.eclipse.che.plugin.languageserver.ide.window;

import com.google.inject.Inject;
import com.google.inject.Singleton;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/

package org.eclipse.che.plugin.languageserver.ide.window;

import org.eclipse.che.api.core.jsonrpc.commons.JsonRpcPromise;
import org.eclipse.che.plugin.languageserver.ide.window.dialog.MessageDialogPresenter;
import org.eclipse.lsp4j.MessageActionItem;
import org.eclipse.lsp4j.ShowMessageRequestParams;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;

/**
** A processor for incoming <code>window/showMessageRequest</code> requests sent
* by a language server.
*/
@Singleton
public class ShowMessageRequestProcessor {

private final Provider<MessageDialogPresenter> provider;

@Inject
public ShowMessageRequestProcessor(Provider<MessageDialogPresenter> provider) {
this.provider = provider;
}

public JsonRpcPromise<MessageActionItem> processNotificationRequest(ShowMessageRequestParams params) {
JsonRpcPromise<MessageActionItem> result = new JsonRpcPromise<>();

MessageDialogPresenter dialogPresenter = provider.get();
dialogPresenter.show(params.getMessage(), params.getType().toString(), params.getActions(), actionItem -> {
result.getSuccessConsumer().ifPresent(consumer -> consumer.accept("ws-agent", actionItem));
});

return result;
}
}
Loading

0 comments on commit a8d3206

Please sign in to comment.