/*******************************************************************************
 * 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.api.machine.server.terminal;

import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.api.machine.server.MachineManager;
import org.eclipse.che.api.machine.server.exception.MachineException;
import org.eclipse.che.api.machine.server.spi.Instance;
import org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

import static java.util.stream.Collectors.toMap;

/**
 * Starts websocket terminal in the machine after its start.
 *
 * @author Alexander Garagatyi
 */
@Singleton
public class MachineTerminalLauncher {
    private static final Logger LOG = LoggerFactory.getLogger(MachineTerminalLauncher.class);

    private final EventService                                     eventService;
    private final MachineManager                                   machineManager;
    private final Map<String, MachineImplSpecificTerminalLauncher> terminalLaunchers;

    @Inject
    public MachineTerminalLauncher(EventService eventService,
                                   MachineManager machineManager,
                                   Set<MachineImplSpecificTerminalLauncher> machineImplLaunchers) {
        this.eventService = eventService;
        this.machineManager = machineManager;
        this.terminalLaunchers = machineImplLaunchers.stream()
                                                     .collect(toMap(MachineImplSpecificTerminalLauncher::getMachineType,
                                                                    Function.identity()));
    }

    @PostConstruct
    public void start() {
        eventService.subscribe(new EventSubscriber<MachineStatusEvent>() {
            @Override
            public void onEvent(MachineStatusEvent event) {
                if (event.getEventType() == MachineStatusEvent.EventType.RUNNING) {
                    try {
                        final Instance machine = machineManager.getInstance(event.getMachineId());

                        MachineImplSpecificTerminalLauncher terminalLauncher = terminalLaunchers.get(machine.getConfig()
                                                                                                            .getType());
                        if (terminalLauncher == null) {
                            LOG.warn("Terminal launcher implementation was not found for machine {} with type {}.",
                                     machine.getId(),
                                     machine.getConfig().getType());
                        } else {
                            terminalLauncher.launchTerminal(machine);
                        }
                    } catch (MachineException | NotFoundException e) {
                        LOG.error(e.getLocalizedMessage(), e);
                        // TODO send event that terminal is unavailable
                    }
                }
            }
        });
    }
}

@@ -569,16 +569,80 @@
 minal;%0A%0A
+import com.google.common.util.concurrent.ThreadFactoryBuilder;%0A%0A
 import o
@@ -1261,16 +1261,100 @@
 il.Set;%0A
+import java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.Executors;%0A
 import j
@@ -1929,16 +1929,93 @@
 unchers;
+%0A    private final ExecutorService                                  executor;
 %0A%0A    @I
@@ -2607,24 +2607,338 @@
 entity()));%0A
+        this.executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat(%22MachineTerminalLauncher-%25d%22)%0A                                                                                .setDaemon(true)%0A                                                                                .build());%0A%0A
     %7D%0A%0A    @
@@ -3214,24 +3214,73 @@
 .RUNNING) %7B%0A
+                    executor.execute(() -%3E %7B%0A    
             
@@ -3293,16 +3293,20 @@
   try %7B%0A
+    
         
@@ -3417,24 +3417,28 @@
             
+    
 MachineImplS
@@ -3522,16 +3522,20 @@
 onfig()%0A
+    
         
@@ -3667,24 +3667,28 @@
             
+    
 if (terminal
@@ -3703,24 +3703,28 @@
  == null) %7B%0A
+    
             
@@ -3856,32 +3856,36 @@
                 
+    
 machine.getId(),
@@ -3914,32 +3914,36 @@
                 
+ 
+   
 machine.getConfi
@@ -3950,32 +3950,36 @@
 g().getType());%0A
+    
                 
@@ -4023,16 +4023,20 @@
         
+    
 terminal
@@ -4085,34 +4085,42 @@
                 
+   
+ 
 %7D%0A
+    
                 
@@ -4194,24 +4194,28 @@
             
+  
+  
 LOG.error(e.
@@ -4237,24 +4237,28 @@
 sage(), e);%0A
+    
             
@@ -4329,33 +4329,61 @@
                 
+ 
-%7D
+   %7D%0A                    %7D);
 %0A               

fix lack of machine running events on clients (#1140)