/******************************************************************************* * 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.machine; import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.machine.shared.dto.MachineStateDto; import org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; import org.eclipse.che.api.workspace.shared.dto.UsersWorkspaceDto; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; import org.eclipse.che.ide.extension.machine.client.machine.events.MachineStateEvent; 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.eclipse.che.api.workspace.gwt.client.event.StartWorkspaceEvent; import org.eclipse.che.api.workspace.gwt.client.event.StartWorkspaceHandler; import javax.validation.constraints.NotNull; import static org.eclipse.che.api.machine.gwt.client.MachineManager.MachineOperationType; import static org.eclipse.che.api.machine.gwt.client.MachineManager.MachineOperationType.RESTART; 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; /** * Notifies about changing machine state. * * @author Artem Zatsarynnyi */ @Singleton class MachineStatusNotifier { /** WebSocket channel to receive messages about changing machine state. */ public static final String MACHINE_STATUS_WS_CHANNEL = "machine:status:"; private final EventBus eventBus; private final DtoUnmarshallerFactory dtoUnmarshallerFactory; private final AppContext appContext; private final NotificationManager notificationManager; private final MachineLocalizationConstant locale; private MessageBus messageBus; @Inject MachineStatusNotifier(EventBus eventBus, DtoUnmarshallerFactory dtoUnmarshallerFactory, AppContext appContext, final MessageBusProvider messageBusProvider, NotificationManager notificationManager, MachineLocalizationConstant locale) { this.eventBus = eventBus; this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; this.appContext = appContext; this.notificationManager = notificationManager; this.locale = locale; this.messageBus = messageBusProvider.getMessageBus(); eventBus.addHandler(StartWorkspaceEvent.TYPE, new StartWorkspaceHandler() { @Override public void onWorkspaceStarted(UsersWorkspaceDto workspace) { messageBus = messageBusProvider.getMessageBus(); } }); } /** * Start tracking machine state and notify about state changing. * * @param machineState * machine to track */ void trackMachine(MachineStateDto machineState, MachineOperationType operationType) { trackMachine(machineState, null, operationType); } /** * Start tracking machine state and notify about state changing. * * @param machineState * machine to track * @param runningListener * listener that will be notified when machine is running */ void trackMachine(final MachineStateDto machineState, final RunningListener runningListener, final MachineOperationType operationType) { final String machineName = machineState.getName(); final String workspaceId = appContext.getWorkspace().getId(); final String wsChannel = MACHINE_STATUS_WS_CHANNEL + workspaceId + ":" + machineName; final StatusNotification notification = notificationManager.notify("", PROGRESS, false); final Unmarshallable<MachineStatusEvent> unmarshaller = dtoUnmarshallerFactory.newWSUnmarshaller(MachineStatusEvent.class); final MessageHandler messageHandler = new SubscriptionHandler<MachineStatusEvent>(unmarshaller) { @Override protected void onMessageReceived(MachineStatusEvent result) { switch (result.getEventType()) { case RUNNING: unsubscribe(wsChannel, this); if (runningListener != null) { runningListener.onRunning(); } final String message = RESTART.equals(operationType) ? locale.machineRestarted(machineName) : locale.notificationMachineIsRunning(machineName); notification.setTitle(message); notification.setStatus(SUCCESS); eventBus.fireEvent(MachineStateEvent.createMachineRunningEvent(machineState)); break; case DESTROYED: unsubscribe(wsChannel, this); notification.setStatus(SUCCESS); notification.setTitle(locale.notificationMachineDestroyed(machineName)); eventBus.fireEvent(MachineStateEvent.createMachineDestroyedEvent(machineState)); break; case ERROR: unsubscribe(wsChannel, this); notification.setStatus(FAIL); notification.setTitle(result.getError()); break; } } @Override protected void onErrorReceived(Throwable exception) { unsubscribe(wsChannel, this); notification.setStatus(FAIL); } }; switch (operationType) { case START: notification.setTitle(locale.notificationCreatingMachine(machineName)); break; case RESTART: notification.setTitle(locale.notificationMachineRestarting(machineName)); break; case DESTROY: notification.setTitle(locale.notificationDestroyingMachine(machineName)); break; } notification.setStatus(PROGRESS); subscribe(wsChannel, messageHandler); } private void subscribe(@NotNull String wsChannel, @NotNull MessageHandler handler) { try { messageBus.subscribe(wsChannel, handler); } catch (WebSocketException e) { Log.error(getClass(), e); } } private void unsubscribe(@NotNull String wsChannel, @NotNull MessageHandler handler) { try { messageBus.unsubscribe(wsChannel, handler); } catch (WebSocketException e) { Log.error(getClass(), e); } } /** Listener's method will be invoked when machine is running. */ interface RunningListener { void onRunning(); } }