Skip to content

Commit b95d74c

Browse files
authored
Broadcast project import output through json rpc protocol (eclipse-che#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
1 parent c34d359 commit b95d74c

21 files changed

Lines changed: 800 additions & 111 deletions

File tree

core/che-core-api-core/src/main/java/org/eclipse/che/api/core/jsonrpc/commons/RequestHandlerManager.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,45 @@ public boolean isRegistered(String method) {
134134
return methodToCategory.containsKey(method);
135135
}
136136

137+
public synchronized boolean deregister(String method) {
138+
Category category = methodToCategory.remove(method);
139+
140+
if (category == null) {
141+
return false;
142+
}
143+
144+
switch (category) {
145+
case ONE_TO_ONE:
146+
oneToOneHandlers.remove(method);
147+
break;
148+
case ONE_TO_MANY:
149+
oneToManyHandlers.remove(method);
150+
break;
151+
case ONE_TO_NONE:
152+
oneToNoneHandlers.remove(method);
153+
break;
154+
case MANY_TO_ONE:
155+
manyToOneHandlers.remove(method);
156+
break;
157+
case MANY_TO_MANY:
158+
manyToManyHandlers.remove(method);
159+
break;
160+
case MANY_TO_NONE:
161+
manyToNoneHandlers.remove(method);
162+
break;
163+
case NONE_TO_ONE:
164+
noneToOneHandlers.remove(method);
165+
break;
166+
case NONE_TO_MANY:
167+
noneToManyHandlers.remove(method);
168+
break;
169+
case NONE_TO_NONE:
170+
noneToNoneHandlers.remove(method);
171+
}
172+
173+
return true;
174+
}
175+
137176
public void handle(String endpointId, String requestId, String method, JsonRpcParams params) {
138177
mustBeRegistered(method);
139178

ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/ProjectImportModule.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import org.eclipse.che.ide.api.project.wizard.ProjectNotificationSubscriber;
2424
import org.eclipse.che.ide.projectimport.wizard.ImportWizardFactory;
2525
import org.eclipse.che.ide.projectimport.wizard.ImportWizardRegistryImpl;
26-
import org.eclipse.che.ide.projectimport.wizard.ProjectNotificationSubscriberImpl;
26+
import org.eclipse.che.ide.projectimport.wizard.ProjectImportOutputJsonRpcNotifier;
2727
import org.eclipse.che.ide.projectimport.zip.ZipImportWizardRegistrar;
2828

2929
/**
@@ -43,9 +43,8 @@ protected void configure() {
4343

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

46-
bind(ProjectNotificationSubscriber.class).to(ProjectNotificationSubscriberImpl.class).in(Singleton.class);
4746
install(new GinFactoryModuleBuilder()
48-
.implement(ProjectNotificationSubscriber.class, ProjectNotificationSubscriberImpl.class)
47+
.implement(ProjectNotificationSubscriber.class, ProjectImportOutputJsonRpcNotifier.class)
4948
.build(ImportProjectNotificationSubscriberFactory.class));
5049
}
5150
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2012-2017 Codenvy, S.A.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Codenvy, S.A. - initial API and implementation
10+
*******************************************************************************/
11+
package org.eclipse.che.ide.projectimport.wizard;
12+
13+
import com.google.inject.Inject;
14+
import com.google.inject.Singleton;
15+
import com.google.web.bindery.event.shared.EventBus;
16+
17+
import org.eclipse.che.ide.CoreLocalizationConstant;
18+
import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent;
19+
import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler;
20+
import org.eclipse.che.ide.api.notification.NotificationManager;
21+
import org.eclipse.che.ide.api.notification.StatusNotification;
22+
import org.eclipse.che.ide.api.project.wizard.ProjectNotificationSubscriber;
23+
24+
import static com.google.common.base.Strings.nullToEmpty;
25+
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE;
26+
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
27+
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PROGRESS;
28+
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
29+
30+
/**
31+
* Json RPC based implementation of the {@link ProjectNotificationSubscriber} which notifies user
32+
* about output events via popup notification.
33+
*
34+
* @author Vlad Zhukovskyi
35+
* @since 5.9.0
36+
*/
37+
@Singleton
38+
public class ProjectImportOutputJsonRpcNotifier implements ProjectNotificationSubscriber {
39+
40+
private final NotificationManager notificationManager;
41+
private final ProjectImportOutputJsonRpcSubscriber subscriber;
42+
private final CoreLocalizationConstant locale;
43+
44+
private StatusNotification singletonNotification;
45+
private String projectName;
46+
47+
@Inject
48+
public ProjectImportOutputJsonRpcNotifier(NotificationManager notificationManager,
49+
ProjectImportOutputJsonRpcSubscriber subscriber,
50+
CoreLocalizationConstant locale,
51+
EventBus eventBus) {
52+
this.notificationManager = notificationManager;
53+
this.subscriber = subscriber;
54+
this.locale = locale;
55+
56+
eventBus.addHandler(WsAgentStateEvent.TYPE, new WsAgentStateHandler() {
57+
@Override
58+
public void onWsAgentStarted(WsAgentStateEvent event) {
59+
}
60+
61+
@Override
62+
public void onWsAgentStopped(WsAgentStateEvent event) {
63+
subscriber.unSubscribeForImportOutputEvents();
64+
65+
singletonNotification.setStatus(FAIL);
66+
singletonNotification.setContent("");
67+
}
68+
});
69+
}
70+
71+
@Override
72+
public void subscribe(String projectName, StatusNotification notification) {
73+
this.projectName = projectName;
74+
this.singletonNotification = notification;
75+
76+
subscriber.subscribeForImportOutputEvents(progressRecord -> {
77+
ProjectImportOutputJsonRpcNotifier.this.projectName = nullToEmpty(progressRecord.getProjectName());
78+
singletonNotification.setTitle(locale.importingProject(ProjectImportOutputJsonRpcNotifier.this.projectName));
79+
singletonNotification.setContent(nullToEmpty(progressRecord.getLine()));
80+
});
81+
}
82+
83+
@Override
84+
public void subscribe(String projectName) {
85+
singletonNotification = notificationManager.notify(locale.importingProject(projectName), PROGRESS, FLOAT_MODE);
86+
subscribe(projectName, singletonNotification);
87+
}
88+
89+
@Override
90+
public void onSuccess() {
91+
subscriber.unSubscribeForImportOutputEvents();
92+
93+
singletonNotification.setStatus(SUCCESS);
94+
singletonNotification.setTitle(locale.importProjectMessageSuccess(projectName));
95+
singletonNotification.setContent("");
96+
}
97+
98+
@Override
99+
public void onFailure(String errorMessage) {
100+
subscriber.unSubscribeForImportOutputEvents();
101+
102+
singletonNotification.setStatus(FAIL);
103+
singletonNotification.setContent(errorMessage);
104+
}
105+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2012-2017 Codenvy, S.A.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Codenvy, S.A. - initial API and implementation
10+
*******************************************************************************/
11+
package org.eclipse.che.ide.projectimport.wizard;
12+
13+
import com.google.inject.Inject;
14+
import com.google.inject.Singleton;
15+
16+
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
17+
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerManager;
18+
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
19+
import org.eclipse.che.api.project.shared.ImportProgressRecord;
20+
import org.eclipse.che.api.project.shared.dto.ImportProgressRecordDto;
21+
22+
import java.util.function.Consumer;
23+
24+
import static org.eclipse.che.api.project.shared.Constants.EVENT_IMPORT_OUTPUT_PROGRESS;
25+
import static org.eclipse.che.api.project.shared.Constants.EVENT_IMPORT_OUTPUT_SUBSCRIBE;
26+
import static org.eclipse.che.api.project.shared.Constants.EVENT_IMPORT_OUTPUT_UN_SUBSCRIBE;
27+
28+
/**
29+
* Json RPC subscriber for listening to the project import events. Register itself for the listening events from the server side.
30+
*
31+
* @author Vlad Zhukovskyi
32+
* @since 5.9.0
33+
*/
34+
@Singleton
35+
public class ProjectImportOutputJsonRpcSubscriber {
36+
37+
public static final String WS_AGENT_ENDPOINT = "ws-agent";
38+
39+
private final RequestTransmitter transmitter;
40+
private final RequestHandlerConfigurator configurator;
41+
private final RequestHandlerManager requestHandlerManager;
42+
43+
@Inject
44+
public ProjectImportOutputJsonRpcSubscriber(RequestTransmitter transmitter,
45+
RequestHandlerConfigurator configurator,
46+
RequestHandlerManager requestHandlerManager) {
47+
this.transmitter = transmitter;
48+
this.configurator = configurator;
49+
this.requestHandlerManager = requestHandlerManager;
50+
}
51+
52+
protected void subscribeForImportOutputEvents(Consumer<ImportProgressRecord> progressConsumer) {
53+
transmitter.newRequest().endpointId(WS_AGENT_ENDPOINT).methodName(EVENT_IMPORT_OUTPUT_SUBSCRIBE).noParams().sendAndSkipResult();
54+
55+
configurator.newConfiguration()
56+
.methodName(EVENT_IMPORT_OUTPUT_PROGRESS)
57+
.paramsAsDto(ImportProgressRecordDto.class)
58+
.noResult()
59+
.withConsumer(progress -> progressConsumer.accept(progress));
60+
}
61+
62+
protected void unSubscribeForImportOutputEvents() {
63+
transmitter.newRequest().endpointId(WS_AGENT_ENDPOINT).methodName(EVENT_IMPORT_OUTPUT_UN_SUBSCRIBE).noParams().sendAndSkipResult();
64+
65+
requestHandlerManager.deregister(EVENT_IMPORT_OUTPUT_PROGRESS);
66+
}
67+
}

ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projectimport/wizard/ProjectNotificationSubscriberImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
* It can be produced by {@code ImportProjectNotificationSubscriberFactory}
4141
*
4242
* @author Anton Korneta
43+
* @deprecated this class is going to be removed soon
4344
*/
45+
@Deprecated
4446
@Singleton
4547
public class ProjectNotificationSubscriberImpl implements ProjectNotificationSubscriber {
4648

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2012-2017 Codenvy, S.A.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Codenvy, S.A. - initial API and implementation
10+
*******************************************************************************/
11+
package org.eclipse.che.ide.projectimport.wizard;
12+
13+
import com.google.gwtmockito.GwtMockitoTestRunner;
14+
import com.google.web.bindery.event.shared.EventBus;
15+
16+
import org.eclipse.che.api.project.shared.ImportProgressRecord;
17+
import org.eclipse.che.ide.CoreLocalizationConstant;
18+
import org.eclipse.che.ide.api.notification.NotificationManager;
19+
import org.eclipse.che.ide.api.notification.StatusNotification;
20+
import org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode;
21+
import org.eclipse.che.ide.api.notification.StatusNotification.Status;
22+
import org.junit.Before;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.mockito.ArgumentCaptor;
26+
import org.mockito.Mock;
27+
28+
import java.util.function.Consumer;
29+
30+
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
31+
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
32+
import static org.mockito.Matchers.any;
33+
import static org.mockito.Matchers.anyString;
34+
import static org.mockito.Matchers.eq;
35+
import static org.mockito.Mockito.mock;
36+
import static org.mockito.Mockito.verify;
37+
import static org.mockito.Mockito.when;
38+
39+
/**
40+
* Unit tests for {@link ProjectImportOutputJsonRpcNotifier}.
41+
*
42+
* @author Vlad Zhukovskyi
43+
*/
44+
@RunWith(GwtMockitoTestRunner.class)
45+
public class ProjectImportOutputJsonRpcNotifierTest {
46+
47+
@Mock
48+
NotificationManager notificationManager;
49+
@Mock
50+
ProjectImportOutputJsonRpcSubscriber subscriber;
51+
@Mock
52+
CoreLocalizationConstant constant;
53+
@Mock
54+
EventBus eventBus;
55+
56+
private ProjectImportOutputJsonRpcNotifier notifier;
57+
58+
@Before
59+
public void setUp() throws Exception {
60+
notifier = new ProjectImportOutputJsonRpcNotifier(notificationManager, subscriber, constant, eventBus);
61+
}
62+
63+
@Test
64+
public void testShouldSubscribeForDisplayingNotification() throws Exception {
65+
//given
66+
final ImportProgressRecord dto = new ImportProgressRecord() {
67+
@Override
68+
public int getNum() {
69+
return 1;
70+
}
71+
72+
@Override
73+
public String getLine() {
74+
return "message";
75+
}
76+
77+
@Override
78+
public String getProjectName() {
79+
return "project";
80+
}
81+
};
82+
83+
final ArgumentCaptor<Consumer> argumentCaptor = ArgumentCaptor.forClass(Consumer.class);
84+
final StatusNotification statusNotification = mock(StatusNotification.class);
85+
when(notificationManager.notify(anyString(), any(Status.class), any(DisplayMode.class))).thenReturn(statusNotification);
86+
when(constant.importingProject(anyString())).thenReturn("message");
87+
88+
//when
89+
notifier.subscribe("project");
90+
91+
//then
92+
verify(constant).importingProject(eq("project"));
93+
verify(subscriber).subscribeForImportOutputEvents(argumentCaptor.capture());
94+
argumentCaptor.getValue().accept(dto);
95+
verify(statusNotification).setTitle(eq("message"));
96+
verify(statusNotification).setContent(eq(dto.getLine()));
97+
}
98+
99+
@Test
100+
public void testShouldUnSubscribeFromDisplayingNotification() throws Exception {
101+
//given
102+
when(constant.importProjectMessageSuccess(anyString())).thenReturn("message");
103+
final StatusNotification statusNotification = mock(StatusNotification.class);
104+
when(notificationManager.notify(anyString(), any(Status.class), any(DisplayMode.class))).thenReturn(statusNotification);
105+
106+
//when
107+
notifier.subscribe("project");
108+
notifier.onSuccess();
109+
110+
//then
111+
verify(subscriber).unSubscribeForImportOutputEvents();
112+
verify(statusNotification).setStatus(eq(SUCCESS));
113+
verify(statusNotification).setTitle(eq("message"));
114+
verify(statusNotification).setContent(eq(""));
115+
}
116+
117+
@Test
118+
public void testShouldUnSubscribeFromDisplayingNotificationIfExceptionOccurred() throws Exception {
119+
120+
//given
121+
final StatusNotification statusNotification = mock(StatusNotification.class);
122+
when(notificationManager.notify(anyString(), any(Status.class), any(DisplayMode.class))).thenReturn(statusNotification);
123+
124+
//when
125+
notifier.subscribe("project");
126+
notifier.onFailure("message");
127+
128+
//then
129+
verify(subscriber).unSubscribeForImportOutputEvents();
130+
verify(statusNotification).setStatus(eq(FAIL));
131+
verify(statusNotification).setContent(eq("message"));
132+
133+
}
134+
}

wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ public class Constants {
3737
public static final String COMMANDS_ATTRIBUTE_NAME = "commands";
3838
public static final String COMMANDS_ATTRIBUTE_DESCRIPTION = "Project-related commands";
3939

40+
public static final String EVENT_IMPORT_OUTPUT_SUBSCRIBE = "importProject/subscribe";
41+
public static final String EVENT_IMPORT_OUTPUT_UN_SUBSCRIBE = "importProject/unSubscribe";
42+
public static final String EVENT_IMPORT_OUTPUT_PROGRESS = "importProject/progress";
43+
4044
private Constants() {
4145
}
4246
}

0 commit comments

Comments
 (0)