package com.continuuity.internal.app.runtime.service;

import com.continuuity.app.Id;
import com.continuuity.app.program.Program;
import com.continuuity.app.program.Programs;
import com.continuuity.app.program.Type;
import com.continuuity.app.runtime.AbstractProgramRuntimeService;
import com.continuuity.app.runtime.ProgramOptions;
import com.continuuity.common.conf.CConfiguration;
import com.continuuity.common.conf.Constants;
import com.continuuity.internal.app.runtime.ProgramRunnerFactory;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;

import java.io.File;
import java.io.IOException;

/**
 *
 */
public final class InMemoryProgramRuntimeService extends AbstractProgramRuntimeService {

  private final CConfiguration configuration;

  @Inject
  public InMemoryProgramRuntimeService(ProgramRunnerFactory programRunnerFactory,
                                       CConfiguration configuration) {
    super(programRunnerFactory);
    this.configuration = configuration;
  }

  @Override
  public synchronized RuntimeInfo run(Program program, ProgramOptions options) {
    try {
      // TODO: fix possible issue where two run() calls use the same unpackedLocation
      File destinationUnpackedJarDir = new File(
        configuration.get(Constants.AppFabric.TEMP_DIR) + "/" + program.getName() + "-" + System.currentTimeMillis());
      Preconditions.checkState(!destinationUnpackedJarDir.exists());
      destinationUnpackedJarDir.mkdirs();

      Program bundleJarProgram = Programs.create(program.getJarLocation(), destinationUnpackedJarDir);
      return super.run(bundleJarProgram, options);
    } catch (IOException e) {
      throw new RuntimeException("Error unpackaging program " + program.getName());
    }
  }

  @Override
  public LiveInfo getLiveInfo(Id.Program programId, Type type) {
    return isRunning(programId, type)
      ? new InMemoryLiveInfo(programId, type)
      : new NotRunningLiveInfo(programId, type);
  }
}

@@ -275,16 +275,70 @@
 ervice;%0A
+import com.continuuity.app.runtime.ProgramController;%0A
 import c
@@ -610,62 +610,480 @@
 gle.
-inject.Inject;%0A%0Aimport java.io.File;%0Aimport java.io.IO
+common.collect.Lists;%0Aimport com.google.common.util.concurrent.Futures;%0Aimport com.google.common.util.concurrent.ListenableFuture;%0Aimport com.google.inject.Inject;%0Aimport org.apache.twill.api.RunId;%0Aimport org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0Aimport java.io.File;%0Aimport java.io.IOException;%0Aimport java.util.List;%0Aimport java.util.Map;%0Aimport java.util.concurrent.ExecutionException;%0Aimport java.util.concurrent.TimeUnit;%0Aimport java.util.concurrent.Timeout
 Exce
@@ -1191,16 +1191,115 @@
 vice %7B%0A%0A
+  private static final Logger LOG = LoggerFactory.getLogger(InMemoryProgramRuntimeService.class);%0A%0A
   privat
@@ -2539,11 +2539,1334 @@
 pe);%0A  %7D
+%0A%0A  @Override%0A  protected void shutDown() throws Exception %7B%0A    stopAllPrograms();%0A  %7D%0A%0A  private void stopAllPrograms() %7B%0A%0A    LOG.info(%22Stopping all running programs.%22);%0A%0A    List%3CListenableFuture%3CProgramController%3E%3E futures = Lists.newLinkedList();%0A    for (Type type : Type.values()) %7B%0A      for (Map.Entry%3CRunId, RuntimeInfo%3E entry : list(type).entrySet()) %7B%0A        RuntimeInfo runtimeInfo = entry.getValue();%0A        if (isRunning(runtimeInfo.getProgramId(), type)) %7B%0A          futures.add(runtimeInfo.getController().stop());%0A        %7D%0A      %7D%0A    %7D%0A    // unchecked because we cannot do much if it fails. We will still shutdown the singlenode.%0A    try %7B%0A      Futures.successfulAsList(futures).get(60, TimeUnit.SECONDS);%0A      LOG.info(%22All programs have been stopped.%22);%0A    %7D catch (ExecutionException e) %7B%0A      // note this should not happen because we wait on a successfulAsList%0A      LOG.warn(%22Got exception while waiting for all programs to stop%22, e.getCause());%0A    %7D catch (InterruptedException e) %7B%0A      LOG.warn(%22Got interrupted exception while waiting for all programs to stop%22, e);%0A      Thread.currentThread().interrupt();%0A    %7D catch (TimeoutException e) %7B%0A      // can't do much more than log it. We still want to exit.%0A      LOG.warn(%22Timeout while waiting for all programs to stop.%22);%0A    %7D%0A  %7D
 %0A%7D%0A

make app fabric stop all programs before shutdown, in local mode