/******************************************************************************* * 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.extension.machine.client.outputspanel.console; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.machine.gwt.client.MachineServiceClient; import org.eclipse.che.api.machine.gwt.client.OutputMessageUnmarshaller; import org.eclipse.che.api.machine.shared.dto.MachineProcessDto; import org.eclipse.che.api.machine.shared.dto.event.MachineProcessEvent; 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; import org.eclipse.che.ide.extension.machine.client.processes.event.ProcessFinishedEvent; import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; import org.eclipse.che.ide.util.loging.Log; import org.eclipse.che.ide.websocket.MessageBus; import org.eclipse.che.ide.websocket.MessageBusProvider; import org.eclipse.che.ide.websocket.WebSocketException; import org.eclipse.che.ide.websocket.events.MessageHandler; import org.eclipse.che.ide.websocket.rest.SubscriptionHandler; import org.eclipse.che.ide.websocket.rest.Unmarshallable; import org.vectomatic.dom.svg.ui.SVGResource; import static com.google.common.base.Strings.isNullOrEmpty; import static org.eclipse.che.ide.extension.machine.client.command.edit.EditCommandsPresenter.PREVIEW_URL_ATTR; /** * Console for command output. * * @author Artem Zatsarynnyi */ public class CommandOutputConsolePresenter implements CommandOutputConsole, OutputConsoleView.ActionDelegate { private final OutputConsoleView view; private final DtoUnmarshallerFactory dtoUnmarshallerFactory; private final MachineServiceClient machineServiceClient; private final MachineResources resources; private final CommandConfiguration commandConfiguration; private final EventBus eventBus; private final String machineId; private MessageBus messageBus; private int pid; private String outputChannel; private MessageHandler outputHandler; private boolean isFinished; @Inject public CommandOutputConsolePresenter(OutputConsoleView view, DtoUnmarshallerFactory dtoUnmarshallerFactory, final MessageBusProvider messageBusProvider, MachineServiceClient machineServiceClient, MachineResources resources, CommandManager commandManager, EventBus eventBus, @Assisted CommandConfiguration commandConfiguration, @Assisted String machineId) { this.view = view; this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; this.machineServiceClient = machineServiceClient; this.resources = resources; this.commandConfiguration = commandConfiguration; this.machineId = machineId; this.messageBus = messageBusProvider.getMessageBus(); this.eventBus = eventBus; view.setDelegate(this); final String previewUrl = commandConfiguration.getAttributes().get(PREVIEW_URL_ATTR); if (!isNullOrEmpty(previewUrl)) { view.printPreviewUrl(commandManager.substituteProperties(previewUrl)); } else { view.hidePreview(); } } @Override public void go(AcceptsOneWidget container) { container.setWidget(view); } @Override public CommandConfiguration getCommand() { return commandConfiguration; } @Override public String getTitle() { return commandConfiguration.getName(); } @Override public SVGResource getTitleIcon() { return resources.output(); } @Override public void listenToOutput(String wsChannel) { outputChannel = wsChannel; outputHandler = new SubscriptionHandler<String>(new OutputMessageUnmarshaller()) { @Override protected void onMessageReceived(String result) { view.print(result, result.endsWith("\r")); view.scrollBottom(); } @Override protected void onErrorReceived(Throwable exception) { wsUnsubscribe(outputChannel, this); } }; wsSubscribe(outputChannel, outputHandler); } @Override public void attachToProcess(final MachineProcessDto process) { this.pid = process.getPid(); view.printCommandLine(process.getCommandLine()); final Unmarshallable<MachineProcessEvent> unmarshaller = dtoUnmarshallerFactory.newWSUnmarshaller(MachineProcessEvent.class); final String processStateChannel = "machine:process:" + machineId; final MessageHandler handler = new SubscriptionHandler<MachineProcessEvent>(unmarshaller) { @Override protected void onMessageReceived(MachineProcessEvent result) { final int processId = result.getProcessId(); if (pid != processId) { return; } switch (result.getEventType()) { case STOPPED: isFinished = true; eventBus.fireEvent(new ProcessFinishedEvent()); case ERROR: isFinished = true; eventBus.fireEvent(new ProcessFinishedEvent()); wsUnsubscribe(processStateChannel, this); wsUnsubscribe(outputChannel, outputHandler); String error = result.getError(); if (error == null) { return; } view.print(error, false); view.scrollBottom(); } } @Override protected void onErrorReceived(Throwable exception) { isFinished = true; wsUnsubscribe(processStateChannel, this); wsUnsubscribe(outputChannel, outputHandler); } }; wsSubscribe(processStateChannel, handler); } private void wsSubscribe(String wsChannel, MessageHandler handler) { try { messageBus.subscribe(wsChannel, handler); } catch (WebSocketException e) { Log.error(getClass(), e); } } private void wsUnsubscribe(String wsChannel, MessageHandler handler) { try { messageBus.unsubscribe(wsChannel, handler); } catch (WebSocketException e) { Log.error(getClass(), e); } } @Override public boolean isFinished() { return isFinished; } @Override public void onClose() { machineServiceClient.stopProcess(machineId, pid); } }