Skip to content

Commit

Permalink
Broadcast project import output through json rpc protocol (eclipse-ch…
Browse files Browse the repository at this point in the history
…e#4888)

* Broadcast project import output through json rpc protocol

Signed-off-by: Vladyslav Zhukovskii <vzhukovskii@codenvy.com>

* Remove redundant text

Signed-off-by: Vladyslav Zhukovskii <vzhukovskii@codenvy.com>

* Code refactoring

* Code refactoring

* Name convention

* New line

* Refactor method body

* Add log call

* Extract hardcoded strings to the constants
  • Loading branch information
vzhukovs authored Jun 20, 2017
1 parent c34d359 commit b95d74c
Show file tree
Hide file tree
Showing 21 changed files with 800 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,45 @@ public boolean isRegistered(String method) {
return methodToCategory.containsKey(method);
}

public synchronized boolean deregister(String method) {
Category category = methodToCategory.remove(method);

if (category == null) {
return false;
}

switch (category) {
case ONE_TO_ONE:
oneToOneHandlers.remove(method);
break;
case ONE_TO_MANY:
oneToManyHandlers.remove(method);
break;
case ONE_TO_NONE:
oneToNoneHandlers.remove(method);
break;
case MANY_TO_ONE:
manyToOneHandlers.remove(method);
break;
case MANY_TO_MANY:
manyToManyHandlers.remove(method);
break;
case MANY_TO_NONE:
manyToNoneHandlers.remove(method);
break;
case NONE_TO_ONE:
noneToOneHandlers.remove(method);
break;
case NONE_TO_MANY:
noneToManyHandlers.remove(method);
break;
case NONE_TO_NONE:
noneToNoneHandlers.remove(method);
}

return true;
}

public void handle(String endpointId, String requestId, String method, JsonRpcParams params) {
mustBeRegistered(method);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import org.eclipse.che.ide.api.project.wizard.ProjectNotificationSubscriber;
import org.eclipse.che.ide.projectimport.wizard.ImportWizardFactory;
import org.eclipse.che.ide.projectimport.wizard.ImportWizardRegistryImpl;
import org.eclipse.che.ide.projectimport.wizard.ProjectNotificationSubscriberImpl;
import org.eclipse.che.ide.projectimport.wizard.ProjectImportOutputJsonRpcNotifier;
import org.eclipse.che.ide.projectimport.zip.ZipImportWizardRegistrar;

/**
Expand All @@ -43,9 +43,8 @@ protected void configure() {

install(new GinFactoryModuleBuilder().build(ImportWizardFactory.class));

bind(ProjectNotificationSubscriber.class).to(ProjectNotificationSubscriberImpl.class).in(Singleton.class);
install(new GinFactoryModuleBuilder()
.implement(ProjectNotificationSubscriber.class, ProjectNotificationSubscriberImpl.class)
.implement(ProjectNotificationSubscriber.class, ProjectImportOutputJsonRpcNotifier.class)
.build(ImportProjectNotificationSubscriberFactory.class));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*******************************************************************************
* 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.ide.projectimport.wizard;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;

import org.eclipse.che.ide.CoreLocalizationConstant;
import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent;
import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.notification.StatusNotification;
import org.eclipse.che.ide.api.project.wizard.ProjectNotificationSubscriber;

import static com.google.common.base.Strings.nullToEmpty;
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;

/**
* Json RPC based implementation of the {@link ProjectNotificationSubscriber} which notifies user
* about output events via popup notification.
*
* @author Vlad Zhukovskyi
* @since 5.9.0
*/
@Singleton
public class ProjectImportOutputJsonRpcNotifier implements ProjectNotificationSubscriber {

private final NotificationManager notificationManager;
private final ProjectImportOutputJsonRpcSubscriber subscriber;
private final CoreLocalizationConstant locale;

private StatusNotification singletonNotification;
private String projectName;

@Inject
public ProjectImportOutputJsonRpcNotifier(NotificationManager notificationManager,
ProjectImportOutputJsonRpcSubscriber subscriber,
CoreLocalizationConstant locale,
EventBus eventBus) {
this.notificationManager = notificationManager;
this.subscriber = subscriber;
this.locale = locale;

eventBus.addHandler(WsAgentStateEvent.TYPE, new WsAgentStateHandler() {
@Override
public void onWsAgentStarted(WsAgentStateEvent event) {
}

@Override
public void onWsAgentStopped(WsAgentStateEvent event) {
subscriber.unSubscribeForImportOutputEvents();

singletonNotification.setStatus(FAIL);
singletonNotification.setContent("");
}
});
}

@Override
public void subscribe(String projectName, StatusNotification notification) {
this.projectName = projectName;
this.singletonNotification = notification;

subscriber.subscribeForImportOutputEvents(progressRecord -> {
ProjectImportOutputJsonRpcNotifier.this.projectName = nullToEmpty(progressRecord.getProjectName());
singletonNotification.setTitle(locale.importingProject(ProjectImportOutputJsonRpcNotifier.this.projectName));
singletonNotification.setContent(nullToEmpty(progressRecord.getLine()));
});
}

@Override
public void subscribe(String projectName) {
singletonNotification = notificationManager.notify(locale.importingProject(projectName), PROGRESS, FLOAT_MODE);
subscribe(projectName, singletonNotification);
}

@Override
public void onSuccess() {
subscriber.unSubscribeForImportOutputEvents();

singletonNotification.setStatus(SUCCESS);
singletonNotification.setTitle(locale.importProjectMessageSuccess(projectName));
singletonNotification.setContent("");
}

@Override
public void onFailure(String errorMessage) {
subscriber.unSubscribeForImportOutputEvents();

singletonNotification.setStatus(FAIL);
singletonNotification.setContent(errorMessage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*******************************************************************************
* 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.ide.projectimport.wizard;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerManager;
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
import org.eclipse.che.api.project.shared.ImportProgressRecord;
import org.eclipse.che.api.project.shared.dto.ImportProgressRecordDto;

import java.util.function.Consumer;

import static org.eclipse.che.api.project.shared.Constants.EVENT_IMPORT_OUTPUT_PROGRESS;
import static org.eclipse.che.api.project.shared.Constants.EVENT_IMPORT_OUTPUT_SUBSCRIBE;
import static org.eclipse.che.api.project.shared.Constants.EVENT_IMPORT_OUTPUT_UN_SUBSCRIBE;

/**
* Json RPC subscriber for listening to the project import events. Register itself for the listening events from the server side.
*
* @author Vlad Zhukovskyi
* @since 5.9.0
*/
@Singleton
public class ProjectImportOutputJsonRpcSubscriber {

public static final String WS_AGENT_ENDPOINT = "ws-agent";

private final RequestTransmitter transmitter;
private final RequestHandlerConfigurator configurator;
private final RequestHandlerManager requestHandlerManager;

@Inject
public ProjectImportOutputJsonRpcSubscriber(RequestTransmitter transmitter,
RequestHandlerConfigurator configurator,
RequestHandlerManager requestHandlerManager) {
this.transmitter = transmitter;
this.configurator = configurator;
this.requestHandlerManager = requestHandlerManager;
}

protected void subscribeForImportOutputEvents(Consumer<ImportProgressRecord> progressConsumer) {
transmitter.newRequest().endpointId(WS_AGENT_ENDPOINT).methodName(EVENT_IMPORT_OUTPUT_SUBSCRIBE).noParams().sendAndSkipResult();

configurator.newConfiguration()
.methodName(EVENT_IMPORT_OUTPUT_PROGRESS)
.paramsAsDto(ImportProgressRecordDto.class)
.noResult()
.withConsumer(progress -> progressConsumer.accept(progress));
}

protected void unSubscribeForImportOutputEvents() {
transmitter.newRequest().endpointId(WS_AGENT_ENDPOINT).methodName(EVENT_IMPORT_OUTPUT_UN_SUBSCRIBE).noParams().sendAndSkipResult();

requestHandlerManager.deregister(EVENT_IMPORT_OUTPUT_PROGRESS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
* It can be produced by {@code ImportProjectNotificationSubscriberFactory}
*
* @author Anton Korneta
* @deprecated this class is going to be removed soon
*/
@Deprecated
@Singleton
public class ProjectNotificationSubscriberImpl implements ProjectNotificationSubscriber {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*******************************************************************************
* 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.ide.projectimport.wizard;

import com.google.gwtmockito.GwtMockitoTestRunner;
import com.google.web.bindery.event.shared.EventBus;

import org.eclipse.che.api.project.shared.ImportProgressRecord;
import org.eclipse.che.ide.CoreLocalizationConstant;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.notification.StatusNotification;
import org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode;
import org.eclipse.che.ide.api.notification.StatusNotification.Status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;

import java.util.function.Consumer;

import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
* Unit tests for {@link ProjectImportOutputJsonRpcNotifier}.
*
* @author Vlad Zhukovskyi
*/
@RunWith(GwtMockitoTestRunner.class)
public class ProjectImportOutputJsonRpcNotifierTest {

@Mock
NotificationManager notificationManager;
@Mock
ProjectImportOutputJsonRpcSubscriber subscriber;
@Mock
CoreLocalizationConstant constant;
@Mock
EventBus eventBus;

private ProjectImportOutputJsonRpcNotifier notifier;

@Before
public void setUp() throws Exception {
notifier = new ProjectImportOutputJsonRpcNotifier(notificationManager, subscriber, constant, eventBus);
}

@Test
public void testShouldSubscribeForDisplayingNotification() throws Exception {
//given
final ImportProgressRecord dto = new ImportProgressRecord() {
@Override
public int getNum() {
return 1;
}

@Override
public String getLine() {
return "message";
}

@Override
public String getProjectName() {
return "project";
}
};

final ArgumentCaptor<Consumer> argumentCaptor = ArgumentCaptor.forClass(Consumer.class);
final StatusNotification statusNotification = mock(StatusNotification.class);
when(notificationManager.notify(anyString(), any(Status.class), any(DisplayMode.class))).thenReturn(statusNotification);
when(constant.importingProject(anyString())).thenReturn("message");

//when
notifier.subscribe("project");

//then
verify(constant).importingProject(eq("project"));
verify(subscriber).subscribeForImportOutputEvents(argumentCaptor.capture());
argumentCaptor.getValue().accept(dto);
verify(statusNotification).setTitle(eq("message"));
verify(statusNotification).setContent(eq(dto.getLine()));
}

@Test
public void testShouldUnSubscribeFromDisplayingNotification() throws Exception {
//given
when(constant.importProjectMessageSuccess(anyString())).thenReturn("message");
final StatusNotification statusNotification = mock(StatusNotification.class);
when(notificationManager.notify(anyString(), any(Status.class), any(DisplayMode.class))).thenReturn(statusNotification);

//when
notifier.subscribe("project");
notifier.onSuccess();

//then
verify(subscriber).unSubscribeForImportOutputEvents();
verify(statusNotification).setStatus(eq(SUCCESS));
verify(statusNotification).setTitle(eq("message"));
verify(statusNotification).setContent(eq(""));
}

@Test
public void testShouldUnSubscribeFromDisplayingNotificationIfExceptionOccurred() throws Exception {

//given
final StatusNotification statusNotification = mock(StatusNotification.class);
when(notificationManager.notify(anyString(), any(Status.class), any(DisplayMode.class))).thenReturn(statusNotification);

//when
notifier.subscribe("project");
notifier.onFailure("message");

//then
verify(subscriber).unSubscribeForImportOutputEvents();
verify(statusNotification).setStatus(eq(FAIL));
verify(statusNotification).setContent(eq("message"));

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public class Constants {
public static final String COMMANDS_ATTRIBUTE_NAME = "commands";
public static final String COMMANDS_ATTRIBUTE_DESCRIPTION = "Project-related commands";

public static final String EVENT_IMPORT_OUTPUT_SUBSCRIBE = "importProject/subscribe";
public static final String EVENT_IMPORT_OUTPUT_UN_SUBSCRIBE = "importProject/unSubscribe";
public static final String EVENT_IMPORT_OUTPUT_PROGRESS = "importProject/progress";

private Constants() {
}
}
Loading

0 comments on commit b95d74c

Please sign in to comment.