From cdf6d97e714b963e09c5e30bbcbe4d9206816717 Mon Sep 17 00:00:00 2001 From: Artem Zatsarynnyi Date: Thu, 30 Jun 2016 19:19:11 +0300 Subject: [PATCH] CHE-1362: make commands execution less error prone --- .../CommandOutputMessageUnmarshaller.java | 49 +++++++++++++++++++ .../che/ide/api/machine/DevMachine.java | 6 +++ .../client/command/CommandManager.java | 16 +++--- .../console/CommandConsoleFactory.java | 3 +- .../CommandOutputConsolePresenter.java | 23 ++++----- .../processes/ConsolesPanelPresenter.java | 24 ++++----- .../processes/ConsolesPanelPresenterTest.java | 2 +- 7 files changed, 90 insertions(+), 33 deletions(-) create mode 100644 ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/CommandOutputMessageUnmarshaller.java diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/CommandOutputMessageUnmarshaller.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/CommandOutputMessageUnmarshaller.java new file mode 100644 index 00000000000..845369c7d19 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/CommandOutputMessageUnmarshaller.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 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.api.machine; + +import com.google.gwt.json.client.JSONParser; +import com.google.gwt.json.client.JSONString; + +import org.eclipse.che.ide.websocket.Message; +import org.eclipse.che.ide.websocket.rest.Unmarshallable; + +/** + * Unmarshaller for websocket messages from machine. + * + * @author Artem Zatsarynnyi + */ +public class CommandOutputMessageUnmarshaller implements Unmarshallable { + + private final String machineName; + private String payload; + + public CommandOutputMessageUnmarshaller(String machineName) { + this.machineName = machineName; + } + + @Override + public void unmarshal(Message message) { + final JSONString jsonString = JSONParser.parseStrict(message.getBody()).isString(); + payload = jsonString.stringValue(); + + if (payload.startsWith("[STDOUT]")) { + payload = payload.substring(9); + } else if (payload.startsWith("[STDERR]")) { + payload = payload.replace("[STDERR]", "[" + machineName + "]"); + } + } + + @Override + public String getPayload() { + return payload; + } +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/DevMachine.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/DevMachine.java index c8a1ed0d9a7..fd0bca14d20 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/DevMachine.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/DevMachine.java @@ -12,6 +12,7 @@ import com.google.common.base.Strings; +import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.api.core.rest.shared.dto.Link; import org.eclipse.che.api.machine.shared.Constants; import org.eclipse.che.api.machine.shared.dto.MachineDto; @@ -139,4 +140,9 @@ public String getAddress() { final DevMachineServer server = getServer(Constants.WSAGENT_REFERENCE); return server.getProtocol() + "://" + server.getAddress(); } + + /** Returns {@link Machine descriptor} of the Workspace Agent. */ + public Machine getDescriptor() { + return devMachineDescriptor; + } } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandManager.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandManager.java index c469bf46082..36f50de9014 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandManager.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandManager.java @@ -90,17 +90,17 @@ public CommandManager(DtoFactory dtoFactory, * machine in which command will be executed */ public void execute(@NotNull CommandConfiguration command, @NotNull Machine machine) { - executeCommand(command, machine.getId()); + executeCommand(command, machine); } /** Execute the the given command configuration on the developer machine. */ public void execute(@NotNull CommandConfiguration configuration) { - final String devMachineId = appContext.getDevMachine().getId(); - executeCommand(configuration, devMachineId); + final Machine devMachine = appContext.getDevMachine().getDescriptor(); + executeCommand(configuration, devMachine); } - public void executeCommand(@NotNull final CommandConfiguration configuration, @NotNull final String machineId) { - if (machineId == null) { + public void executeCommand(@NotNull final CommandConfiguration configuration, @NotNull final Machine machine) { + if (machine == null) { notificationManager.notify(localizationConstant.failedToExecuteCommand(), localizationConstant.noDevMachine(), FAIL, @@ -110,9 +110,9 @@ public void executeCommand(@NotNull final CommandConfiguration configuration, @N final String outputChannel = "process:output:" + UUID.uuid(); - final CommandOutputConsole console = commandConsoleFactory.create(configuration, machineId); + final CommandOutputConsole console = commandConsoleFactory.create(configuration, machine); console.listenToOutput(outputChannel); - consolesPanelPresenter.addCommandOutput(machineId, console); + consolesPanelPresenter.addCommandOutput(machine.getId(), console); workspaceAgent.setActivePart(consolesPanelPresenter); substituteProperties(configuration.toCommandLine()).then(new Operation() { @@ -123,7 +123,7 @@ public void apply(String arg) throws OperationException { .withCommandLine(arg) .withType(configuration.getType().getId()); - final Promise processPromise = machineServiceClient.executeCommand(machineId, command, outputChannel); + final Promise processPromise = machineServiceClient.executeCommand(machine.getId(), command, outputChannel); processPromise.then(new Operation() { @Override public void apply(MachineProcessDto process) throws OperationException { diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandConsoleFactory.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandConsoleFactory.java index 9378902c90f..b873133eeaf 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandConsoleFactory.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandConsoleFactory.java @@ -12,6 +12,7 @@ import com.google.inject.name.Named; +import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.ide.api.outputconsole.OutputConsole; import org.eclipse.che.ide.extension.machine.client.command.CommandConfiguration; @@ -20,7 +21,7 @@ public interface CommandConsoleFactory { /** Create the instance of {@link CommandOutputConsole} for the given {@code commandConfiguration}. */ @Named("command") - CommandOutputConsole create(CommandConfiguration commandConfiguration, String machineId); + CommandOutputConsole create(CommandConfiguration commandConfiguration, Machine machine); /** Create the instance of {@link DefaultOutputConsole} for the given title. */ @Named("default") diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsolePresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsolePresenter.java index 545a6730194..92f8be1e468 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsolePresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsolePresenter.java @@ -15,12 +15,13 @@ import com.google.inject.assistedinject.Assisted; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.ide.api.machine.MachineServiceClient; -import org.eclipse.che.ide.api.machine.OutputMessageUnmarshaller; +import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.api.machine.shared.dto.MachineProcessDto; import org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; +import org.eclipse.che.ide.api.machine.MachineServiceClient; +import org.eclipse.che.ide.api.machine.CommandOutputMessageUnmarshaller; import org.eclipse.che.ide.extension.machine.client.MachineResources; import org.eclipse.che.ide.extension.machine.client.command.CommandConfiguration; import org.eclipse.che.ide.extension.machine.client.command.CommandManager; @@ -54,7 +55,7 @@ public class CommandOutputConsolePresenter implements CommandOutputConsole, Outp private final MachineResources resources; private final CommandConfiguration commandConfiguration; private final EventBus eventBus; - private final String machineId; + private final Machine machine; private final CommandManager commandManager; private MessageBus messageBus; @@ -80,13 +81,13 @@ public CommandOutputConsolePresenter(final OutputConsoleView view, CommandManager commandManager, EventBus eventBus, @Assisted CommandConfiguration commandConfiguration, - @Assisted String machineId) { + @Assisted Machine machine) { this.view = view; this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; this.machineServiceClient = machineServiceClient; this.resources = resources; this.commandConfiguration = commandConfiguration; - this.machineId = machineId; + this.machine = machine; this.messageBus = messageBusProvider.getMessageBus(); this.eventBus = eventBus; this.commandManager = commandManager; @@ -132,7 +133,7 @@ public void listenToOutput(String wsChannel) { view.toggleScrollToEndButton(true); outputChannel = wsChannel; - outputHandler = new SubscriptionHandler(new OutputMessageUnmarshaller()) { + outputHandler = new SubscriptionHandler(new CommandOutputMessageUnmarshaller(machine.getConfig().getName())) { @Override protected void onMessageReceived(String result) { view.print(result, result.endsWith("\r")); @@ -158,7 +159,7 @@ public void attachToProcess(final MachineProcessDto process) { view.showCommandLine(process.getCommandLine()); final Unmarshallable unmarshaller = dtoUnmarshallerFactory.newWSUnmarshaller(MachineProcessEvent.class); - final String processStateChannel = "machine:process:" + machineId; + final String processStateChannel = "machine:process:" + machine.getId(); final MessageHandler handler = new SubscriptionHandler(unmarshaller) { @Override protected void onMessageReceived(MachineProcessEvent result) { @@ -230,7 +231,7 @@ public boolean isFinished() { @Override public void stop() { - machineServiceClient.stopProcess(machineId, pid); + machineServiceClient.stopProcess(machine.getId(), pid); } @Override @@ -246,12 +247,12 @@ public void addOutputListener(ConsoleOutputListener listener) { @Override public void reRunProcessButtonClicked() { if (isFinished()) { - commandManager.executeCommand(commandConfiguration, machineId); + commandManager.executeCommand(commandConfiguration, machine); } else { - machineServiceClient.stopProcess(machineId, pid).then(new Operation() { + machineServiceClient.stopProcess(machine.getId(), pid).then(new Operation() { @Override public void apply(Void arg) throws OperationException { - commandManager.executeCommand(commandConfiguration, machineId); + commandManager.executeCommand(commandConfiguration, machine); } }); } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/ConsolesPanelPresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/ConsolesPanelPresenter.java index fc3657e0639..3f221ea16be 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/ConsolesPanelPresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/ConsolesPanelPresenter.java @@ -16,24 +16,26 @@ import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.ide.api.machine.MachineServiceClient; -import org.eclipse.che.ide.api.machine.events.DevMachineStateEvent; import org.eclipse.che.api.machine.shared.dto.CommandDto; import org.eclipse.che.api.machine.shared.dto.MachineDto; import org.eclipse.che.api.machine.shared.dto.MachineProcessDto; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.api.promises.client.PromiseError; -import org.eclipse.che.ide.api.workspace.event.WorkspaceStartingEvent; -import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.dialogs.ConfirmCallback; +import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.machine.MachineServiceClient; +import org.eclipse.che.ide.api.machine.events.DevMachineStateEvent; import org.eclipse.che.ide.api.mvp.View; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.outputconsole.OutputConsole; import org.eclipse.che.ide.api.parts.HasView; import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.api.parts.base.BasePresenter; +import org.eclipse.che.ide.api.workspace.event.WorkspaceStartingEvent; +import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; import org.eclipse.che.ide.extension.machine.client.MachineResources; @@ -48,8 +50,6 @@ import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandOutputConsole; import org.eclipse.che.ide.extension.machine.client.outputspanel.console.DefaultOutputConsole; import org.eclipse.che.ide.extension.machine.client.perspective.terminal.TerminalPresenter; -import org.eclipse.che.ide.api.dialogs.ConfirmCallback; -import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.extension.machine.client.processes.actions.ConsoleTreeContextMenu; import org.eclipse.che.ide.extension.machine.client.processes.actions.ConsoleTreeContextMenuFactory; import org.eclipse.che.ide.util.loging.Log; @@ -298,13 +298,13 @@ private ProcessTreeNode addMachineNode(MachineDto machine) { view.setProcessesData(rootNode); - restoreState(machine.getId()); + restoreState(machine); return machineNode; } - private void restoreState(final String machineId) { - machineService.getProcesses(machineId).then(new Operation>() { + private void restoreState(final org.eclipse.che.api.core.model.machine.Machine machine) { + machineService.getProcesses(machine.getId()).then(new Operation>() { @Override public void apply(List arg) throws OperationException { for (MachineProcessDto machineProcessDto : arg) { @@ -316,10 +316,10 @@ public void apply(List arg) throws OperationException { final CommandType type = commandTypeRegistry.getCommandTypeById(commandDto.getType()); if (type != null) { final CommandConfiguration configuration = type.getConfigurationFactory().createFromDto(commandDto); - final CommandOutputConsole console = commandConsoleFactory.create(configuration, machineId); + final CommandOutputConsole console = commandConsoleFactory.create(configuration, machine); console.listenToOutput(machineProcessDto.getOutputChannel()); console.attachToProcess(machineProcessDto); - addCommandOutput(machineId, console); + addCommandOutput(machine.getId(), console); } } @@ -327,7 +327,7 @@ public void apply(List arg) throws OperationException { }).catchError(new Operation() { @Override public void apply(PromiseError arg) throws OperationException { - notificationManager.notify(localizationConstant.failedToGetProcesses(machineId)); + notificationManager.notify(localizationConstant.failedToGetProcesses(machine.getId())); } }); } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/ConsolesPanelPresenterTest.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/ConsolesPanelPresenterTest.java index 015f8a2981b..99c10dcf571 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/ConsolesPanelPresenterTest.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/ConsolesPanelPresenterTest.java @@ -171,7 +171,7 @@ public void shouldRestoreState() throws Exception { when(commandTypeRegistry.getCommandTypeById(anyString())).thenReturn(commandType); when(commandType.getConfigurationFactory()).thenReturn(commandConfigurationFactory); when(commandConfigurationFactory.createFromDto(anyObject())).thenReturn(commandConfiguration); - when(commandConsoleFactory.create(anyObject(), anyString())).thenReturn(outputConsole); + when(commandConsoleFactory.create(anyObject(), any(org.eclipse.che.api.core.model.machine.Machine.class))).thenReturn(outputConsole); CommandDto commandDto = mock(CommandDto.class); when(dtoFactory.createDto(anyObject())).thenReturn(commandDto);