@Nullable
  private static RunContentDescriptor chooseReuseContentForDescriptor(
      final ContentManager contentManager, final RunContentDescriptor descriptor) {
    Content content = null;
    if (descriptor != null) {
      if (descriptor.isContentReuseProhibited()) {
        return null;
      }
      final Content attachedContent = descriptor.getAttachedContent();
      if (attachedContent != null && attachedContent.isValid()) content = attachedContent;
    }
    if (content == null) {
      content = contentManager.getSelectedContent();
      if (content != null && content.isPinned()) content = null;
    }
    if (content == null || !isTerminated(content)) {
      return null;
    }
    final RunContentDescriptor oldDescriptor = getRunContentDescriptorByContent(content);
    if (oldDescriptor != null && !oldDescriptor.isContentReuseProhibited()) {
      return oldDescriptor;
    }

    return null;
  }
 private static boolean isTerminated(final Content content) {
   final RunContentDescriptor descriptor = getRunContentDescriptorByContent(content);
   if (descriptor == null) {
     return true;
   } else {
     final ProcessHandler processHandler = descriptor.getProcessHandler();
     return processHandler == null || processHandler.isProcessTerminated();
   }
 }
 public void showRunContent(
     @NotNull final Executor info,
     RunContentDescriptor descriptor,
     RunContentDescriptor contentToReuse) {
   if (contentToReuse != null) {
     descriptor.setAttachedContent(contentToReuse.getAttachedContent());
   }
   showRunContent(info, descriptor);
 }
 public void showRunContent(
     @NotNull final Executor info,
     RunContentDescriptor descriptor,
     RunContentDescriptor contentToReuse) {
   if (contentToReuse != null) {
     final Content attachedContent = contentToReuse.getAttachedContent();
     if (attachedContent.getManager() != null) {
       descriptor.setAttachedContent(attachedContent);
     }
   }
   showRunContent(info, descriptor);
 }
 @Nullable
 private RunContentDescriptor getDescriptorBy(ProcessHandler handler, Executor runnerInfo) {
   ContentManager contentManager = getContentManagerForRunner(runnerInfo);
   Content[] contents = contentManager.getContents();
   for (Content content : contents) {
     RunContentDescriptor runContentDescriptor = content.getUserData(DESCRIPTOR_KEY);
     if (runContentDescriptor.getProcessHandler() == handler) {
       return runContentDescriptor;
     }
   }
   return null;
 }
 public static List<RunContentDescriptor> collectConsolesByDisplayName(
     final Project project, @NotNull NotNullFunction<String, Boolean> titleMatcher) {
   List<RunContentDescriptor> result = Lists.newArrayList();
   final ExecutionManager executionManager = ExecutionManager.getInstance(project);
   final RunContentDescriptor[] runContentDescriptors =
       ((RunContentManagerImpl) executionManager.getContentManager()).getAllDescriptors();
   for (RunContentDescriptor runContentDescriptor : runContentDescriptors) {
     if (titleMatcher.fun(runContentDescriptor.getDisplayName())) {
       result.add(runContentDescriptor);
     }
   }
   return result;
 }
 private Content createNewContent(
     final ContentManager contentManager,
     final RunContentDescriptor descriptor,
     Executor executor) {
   final String processDisplayName = descriptor.getDisplayName();
   final Content content =
       ContentFactory.SERVICE
           .getInstance()
           .createContent(descriptor.getComponent(), processDisplayName, true);
   content.putUserData(DESCRIPTOR_KEY, descriptor);
   content.putUserData(ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE);
   contentManager.addContent(content);
   new CloseListener(content, executor);
   return content;
 }
    @Override
    public void processTerminated(ProcessEvent event) {
      if (myProject.isDisposed()) return;
      if (!myTerminateNotified.compareAndSet(false, true)) return;

      ApplicationManager.getApplication()
          .invokeLater(
              () -> {
                RunnerLayoutUi ui = myDescriptor.getRunnerLayoutUi();
                if (ui != null && !ui.isDisposed()) {
                  ui.updateActionsNow();
                }
              },
              ModalityState.any());

      myProject
          .getMessageBus()
          .syncPublisher(EXECUTION_TOPIC)
          .processTerminated(myExecutorId, myEnvironment, myProcessHandler, event.getExitCode());

      SaveAndSyncHandler saveAndSyncHandler = SaveAndSyncHandler.getInstance();
      if (saveAndSyncHandler != null) {
        saveAndSyncHandler.scheduleRefresh();
      }
    }
 public void restart() {
   final Project project =
       PlatformDataKeys.PROJECT.getData(
           DataManager.getInstance().getDataContext(myDescriptor.getComponent()));
   if (ExecutorRegistry.getInstance()
       .isStarting(project, myExecutor.getId(), myRunner.getRunnerId())) {
     return;
   }
   try {
     final ExecutionEnvironment old = myEnvironment;
     myRunner.execute(
         myExecutor,
         new ExecutionEnvironment(
             old.getRunProfile(),
             old.getExecutionTarget(),
             project,
             old.getRunnerSettings(),
             old.getConfigurationSettings(),
             myDescriptor,
             old.getRunnerAndConfigurationSettings()));
   } catch (RunCanceledByUserException ignore) {
   } catch (ExecutionException e1) {
     Messages.showErrorDialog(
         project, e1.getMessage(), ExecutionBundle.message("restart.error.message.title"));
   }
 }
 boolean isEnabled() {
   ProcessHandler processHandler = myDescriptor.getProcessHandler();
   boolean isTerminating = processHandler != null && processHandler.isProcessTerminating();
   boolean isStarting =
       ExecutorRegistry.getInstance()
           .isStarting(myEnvironment.getProject(), myExecutor.getId(), myRunner.getRunnerId());
   return !isStarting && !isTerminating;
 }
  private void waitForProcess(final RunContentDescriptor descriptor) {
    ProgressManager.getInstance()
        .runProcessWithProgressSynchronously(
            new Runnable() {
              public void run() {
                final Semaphore semaphore = new Semaphore();
                semaphore.down();

                ApplicationManager.getApplication()
                    .executeOnPooledThread(
                        new Runnable() {
                          public void run() {
                            final ProcessHandler processHandler = descriptor.getProcessHandler();
                            try {
                              if (processHandler != null) {
                                processHandler.waitFor();
                              }
                            } finally {
                              semaphore.up();
                            }
                          }
                        });

                final ProgressIndicator progressIndicator =
                    ProgressManager.getInstance().getProgressIndicator();

                if (progressIndicator != null) {
                  progressIndicator.setText(
                      ExecutionBundle.message("waiting.for.vm.detach.progress.text"));
                  ApplicationManager.getApplication()
                      .executeOnPooledThread(
                          new Runnable() {
                            public void run() {
                              while (true) {
                                if (progressIndicator.isCanceled()
                                    || !progressIndicator.isRunning()) {
                                  semaphore.up();
                                  break;
                                }
                                try {
                                  synchronized (this) {
                                    wait(2000L);
                                  }
                                } catch (InterruptedException ignore) {
                                }
                              }
                            }
                          });
                }

                semaphore.waitFor();
              }
            },
            ExecutionBundle.message(
                "terminating.process.progress.title", descriptor.getDisplayName()),
            true,
            myProject);
  }
 public static void restartIfActive(@NotNull RunContentDescriptor descriptor) {
   ProcessHandler processHandler = descriptor.getProcessHandler();
   if (processHandler != null
       && processHandler.isStartNotified()
       && !processHandler.isProcessTerminating()
       && !processHandler.isProcessTerminated()) {
     restart(descriptor);
   }
 }
 @NotNull
 @Override
 public ProcessHandler[] getRunningProcesses() {
   if (myContentManager == null) return EMPTY_PROCESS_HANDLERS;
   List<ProcessHandler> handlers = null;
   for (RunContentDescriptor descriptor : getContentManager().getAllDescriptors()) {
     ProcessHandler processHandler = descriptor.getProcessHandler();
     if (processHandler != null) {
       if (handlers == null) {
         handlers = new SmartList<>();
       }
       handlers.add(processHandler);
     }
   }
   return handlers == null
       ? EMPTY_PROCESS_HANDLERS
       : handlers.toArray(new ProcessHandler[handlers.size()]);
 }
 @Override
 public void restartRunProfile(
     @NotNull Project project,
     @NotNull Executor executor,
     @NotNull ExecutionTarget target,
     @Nullable RunnerAndConfigurationSettings configuration,
     @Nullable ProcessHandler processHandler) {
   ExecutionEnvironmentBuilder builder =
       createEnvironmentBuilder(project, executor, configuration);
   if (processHandler != null) {
     for (RunContentDescriptor descriptor : getContentManager().getAllDescriptors()) {
       if (descriptor.getProcessHandler() == processHandler) {
         builder.contentToReuse(descriptor);
         break;
       }
     }
   }
   restartRunProfile(builder.target(target).build());
 }
    private void dispose() {
      if (myContent == null) return;

      final Content content = myContent;
      try {
        final RunContentDescriptor descriptor = getRunContentDescriptorByContent(content);

        getSyncPublisher().contentRemoved(descriptor, myExecutor);

        descriptor.dispose();
      } finally {
        content.getManager().removeContentManagerListener(this);
        ProjectManager.getInstance().removeProjectManagerListener(this);
        content
            .release(); // don't invoke myContent.release() because myContent becomes null after
                        // destroyProcess()
        myContent = null;
      }
    }
    private boolean closeQuery() {
      final RunContentDescriptor descriptor = getRunContentDescriptorByContent(myContent);

      if (descriptor == null) {
        return true;
      }

      final ProcessHandler processHandler = descriptor.getProcessHandler();
      if (processHandler == null
          || processHandler.isProcessTerminated()
          || processHandler.isProcessTerminating()) {
        return true;
      }
      final boolean destroyProcess;
      if (processHandler.isSilentlyDestroyOnClose()
          || Boolean.TRUE.equals(
              processHandler.getUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE))) {
        destroyProcess = true;
      } else {
        // todo[nik] this is a temporary solution for the following problem: some configurations
        // should not allow user to choose between 'terminating' and 'detaching'
        final boolean useDefault =
            Boolean.TRUE.equals(
                processHandler.getUserData(ALWAYS_USE_DEFAULT_STOPPING_BEHAVIOUR_KEY));
        final TerminateRemoteProcessDialog terminateDialog =
            new TerminateRemoteProcessDialog(
                myProject,
                descriptor.getDisplayName(),
                processHandler.detachIsDefault(),
                useDefault);
        terminateDialog.show();
        if (terminateDialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return false;
        destroyProcess = terminateDialog.forceTermination();
      }
      if (destroyProcess) {
        processHandler.destroyProcess();
      } else {
        processHandler.detachProcess();
      }
      waitForProcess(descriptor);
      return true;
    }
 @Nullable
 private static Content getRunContentByDescriptor(
     final ContentManager contentManager, final RunContentDescriptor descriptor) {
   final Content[] contents = contentManager.getContents();
   for (final Content content : contents) {
     if (descriptor.equals(content.getUserData(DESCRIPTOR_KEY))) {
       return content;
     }
   }
   return null;
 }
  @Override
  public void update(final AnActionEvent event) {
    final Presentation presentation = event.getPresentation();
    String name = myEnvironment.getRunProfile().getName();
    ProcessHandler processHandler = myDescriptor.getProcessHandler();
    final boolean isRunning = processHandler != null && !processHandler.isProcessTerminated();

    presentation.setText(ExecutionBundle.message("rerun.configuration.action.name", name));
    presentation.setIcon(isRunning ? AllIcons.Actions.Restart : myExecutor.getIcon());
    presentation.setEnabled(isEnabled());
  }
  private String constructConsoleTitle(final @NotNull String consoleTitle) {
    if (shouldAddNumberToTitle()) {
      List<RunContentDescriptor> consoles =
          ExecutionHelper.collectConsolesByDisplayName(
              myProject,
              new NotNullFunction<String, Boolean>() {
                @NotNull
                @Override
                public Boolean fun(String dom) {
                  return dom.contains(consoleTitle);
                }
              });
      int max = 0;
      for (RunContentDescriptor dsc : consoles) {
        ProcessHandler handler = dsc.getProcessHandler();
        if (handler != null && !handler.isProcessTerminated()) {
          if (max == 0) {
            max = 1;
          }
          try {
            int num =
                Integer.parseInt(
                    dsc.getDisplayName()
                        .substring(consoleTitle.length() + 1, dsc.getDisplayName().length() - 1));
            if (num > max) {
              max = num;
            }
          } catch (Exception e) {
            // skip
          }
        }
      }
      if (max >= 1) {
        return consoleTitle + "(" + (max + 1) + ")";
      }
    }

    return consoleTitle;
  }
  private static void stop(@Nullable RunContentDescriptor descriptor) {
    ProcessHandler processHandler = descriptor != null ? descriptor.getProcessHandler() : null;
    if (processHandler == null) {
      return;
    }

    if (processHandler instanceof KillableProcess && processHandler.isProcessTerminating()) {
      ((KillableProcess) processHandler).killProcess();
      return;
    }

    if (!processHandler.isProcessTerminated()) {
      if (processHandler.detachIsDefault()) {
        processHandler.detachProcess();
      } else {
        processHandler.destroyProcess();
      }
    }
  }
 private void clearContent(RunContentDescriptor descriptor) {
   Content content = getToolWindow().getContentManager().findContent(descriptor.getDisplayName());
   assert content != null;
   getToolWindow().getContentManager().removeContent(content, true);
 }
 public static boolean isProcessRunning(@Nullable RunContentDescriptor descriptor) {
   ProcessHandler processHandler = descriptor == null ? null : descriptor.getProcessHandler();
   return processHandler != null && !processHandler.isProcessTerminated();
 }
  private static boolean userApprovesStopForIncompatibleConfigurations(
      Project project,
      String configName,
      List<RunContentDescriptor> runningIncompatibleDescriptors) {
    RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(project);
    final RunManagerConfig config = runManager.getConfig();
    if (!config.isStopIncompatibleRequiresConfirmation()) return true;

    DialogWrapper.DoNotAskOption option =
        new DialogWrapper.DoNotAskOption() {
          @Override
          public boolean isToBeShown() {
            return config.isStopIncompatibleRequiresConfirmation();
          }

          @Override
          public void setToBeShown(boolean value, int exitCode) {
            config.setStopIncompatibleRequiresConfirmation(value);
          }

          @Override
          public boolean canBeHidden() {
            return true;
          }

          @Override
          public boolean shouldSaveOptionsOnCancel() {
            return false;
          }

          @NotNull
          @Override
          public String getDoNotShowMessage() {
            return CommonBundle.message("dialog.options.do.not.show");
          }
        };

    final StringBuilder names = new StringBuilder();
    for (final RunContentDescriptor descriptor : runningIncompatibleDescriptors) {
      String name = descriptor.getDisplayName();
      if (names.length() > 0) {
        names.append(", ");
      }
      names.append(
          StringUtil.isEmpty(name)
              ? ExecutionBundle.message("run.configuration.no.name")
              : String.format("'%s'", name));
    }

    //noinspection DialogTitleCapitalization
    return Messages.showOkCancelDialog(
            project,
            ExecutionBundle.message(
                "stop.incompatible.confirmation.message",
                configName,
                names.toString(),
                runningIncompatibleDescriptors.size()),
            ExecutionBundle.message(
                "incompatible.configuration.is.running.dialog.title",
                runningIncompatibleDescriptors.size()),
            ExecutionBundle.message("stop.incompatible.confirmation.button.text"),
            CommonBundle.message("button.cancel"),
            Messages.getQuestionIcon(),
            option)
        == Messages.OK;
  }
  @Override
  public void startRunProfile(
      @NotNull final RunProfileStarter starter,
      @NotNull final RunProfileState state,
      @NotNull final ExecutionEnvironment environment) {
    final Project project = environment.getProject();
    RunContentDescriptor reuseContent = getContentManager().getReuseContent(environment);
    if (reuseContent != null) {
      reuseContent.setExecutionId(environment.getExecutionId());
      environment.setContentToReuse(reuseContent);
    }

    final Executor executor = environment.getExecutor();
    project
        .getMessageBus()
        .syncPublisher(EXECUTION_TOPIC)
        .processStartScheduled(executor.getId(), environment);

    Runnable startRunnable;
    startRunnable =
        () -> {
          if (project.isDisposed()) {
            return;
          }

          RunProfile profile = environment.getRunProfile();
          boolean started = false;
          try {
            project
                .getMessageBus()
                .syncPublisher(EXECUTION_TOPIC)
                .processStarting(executor.getId(), environment);

            final RunContentDescriptor descriptor = starter.execute(state, environment);
            if (descriptor != null) {
              final Trinity<RunContentDescriptor, RunnerAndConfigurationSettings, Executor>
                  trinity =
                      Trinity.create(
                          descriptor, environment.getRunnerAndConfigurationSettings(), executor);
              myRunningConfigurations.add(trinity);
              Disposer.register(descriptor, () -> myRunningConfigurations.remove(trinity));
              getContentManager()
                  .showRunContent(executor, descriptor, environment.getContentToReuse());
              final ProcessHandler processHandler = descriptor.getProcessHandler();
              if (processHandler != null) {
                if (!processHandler.isStartNotified()) {
                  processHandler.startNotify();
                }
                project
                    .getMessageBus()
                    .syncPublisher(EXECUTION_TOPIC)
                    .processStarted(executor.getId(), environment, processHandler);
                started = true;

                ProcessExecutionListener listener =
                    new ProcessExecutionListener(
                        project, executor.getId(), environment, processHandler, descriptor);
                processHandler.addProcessListener(listener);

                // Since we cannot guarantee that the listener is added before process handled is
                // start notified,
                // we have to make sure the process termination events are delivered to the clients.
                // Here we check the current process state and manually deliver events, while
                // the ProcessExecutionListener guarantees each such event is only delivered once
                // either by this code, or by the ProcessHandler.

                boolean terminating = processHandler.isProcessTerminating();
                boolean terminated = processHandler.isProcessTerminated();
                if (terminating || terminated) {
                  listener.processWillTerminate(
                      new ProcessEvent(processHandler), false /*doesn't matter*/);

                  if (terminated) {
                    //noinspection ConstantConditions
                    int exitCode = processHandler.getExitCode();
                    listener.processTerminated(new ProcessEvent(processHandler, exitCode));
                  }
                }
              }
              environment.setContentToReuse(descriptor);
            }
          } catch (ProcessCanceledException e) {
            LOG.info(e);
          } catch (ExecutionException e) {
            ExecutionUtil.handleExecutionError(project, executor.getToolWindowId(), profile, e);
            LOG.info(e);
          } finally {
            if (!started) {
              project
                  .getMessageBus()
                  .syncPublisher(EXECUTION_TOPIC)
                  .processNotStarted(executor.getId(), environment);
            }
          }
        };

    if (ApplicationManager.getApplication().isUnitTestMode() && !myForceCompilationInTests) {
      startRunnable.run();
    } else {
      compileAndRun(
          () -> TransactionGuard.submitTransaction(project, startRunnable),
          environment,
          state,
          () -> {
            if (!project.isDisposed()) {
              project
                  .getMessageBus()
                  .syncPublisher(EXECUTION_TOPIC)
                  .processNotStarted(executor.getId(), environment);
            }
          });
    }
  }
 public static void restart(@NotNull RunContentDescriptor descriptor) {
   restart(descriptor.getComponent());
 }
  public void showRunContent(
      @NotNull final Executor executor, final RunContentDescriptor descriptor) {
    if (ApplicationManager.getApplication().isUnitTestMode()) return;

    final ContentManager contentManager = getContentManagerForRunner(executor);
    RunContentDescriptor oldDescriptor =
        chooseReuseContentForDescriptor(contentManager, descriptor);

    final Content content;

    if (oldDescriptor != null) {
      content = oldDescriptor.getAttachedContent();
      getSyncPublisher().contentRemoved(oldDescriptor, executor);
      oldDescriptor.dispose(); // is of the same category, can be reused
    } else {
      content = createNewContent(contentManager, descriptor, executor);
      final Icon icon = descriptor.getIcon();
      content.setIcon(icon == null ? executor.getToolWindowIcon() : icon);
    }

    content.setComponent(descriptor.getComponent());
    content.putUserData(DESCRIPTOR_KEY, descriptor);
    final ProcessHandler processHandler = descriptor.getProcessHandler();
    if (processHandler != null) {
      final ProcessAdapter processAdapter =
          new ProcessAdapter() {
            public void startNotified(final ProcessEvent event) {
              LaterInvocator.invokeLater(
                  new Runnable() {
                    public void run() {
                      final Icon icon = descriptor.getIcon();
                      content.setIcon(icon == null ? executor.getToolWindowIcon() : icon);
                    }
                  });
            }

            public void processTerminated(final ProcessEvent event) {
              LaterInvocator.invokeLater(
                  new Runnable() {
                    public void run() {
                      final Icon icon = descriptor.getIcon();
                      content.setIcon(
                          icon == null
                              ? executor.getDisabledIcon()
                              : IconLoader.getTransparentIcon(icon));
                    }
                  });
            }
          };
      processHandler.addProcessListener(processAdapter);
      final Disposable disposer = content.getDisposer();
      if (disposer != null) {
        Disposer.register(
            disposer,
            new Disposable() {
              public void dispose() {
                processHandler.removeProcessListener(processAdapter);
              }
            });
      }
    }
    content.setDisplayName(descriptor.getDisplayName());
    descriptor.setAttachedContent(content);
    content.getManager().setSelectedContent(content);

    ApplicationManager.getApplication()
        .invokeLater(
            new Runnable() {
              public void run() {
                ToolWindow window =
                    ToolWindowManager.getInstance(myProject)
                        .getToolWindow(executor.getToolWindowId());
                // let's activate tool window, but don't move focus
                //
                // window.show() isn't valid here, because it will not
                // mark the window as "last activated" windows and thus
                // some action like navigation up/down in stactrace wont
                // work correctly
                window.activate(null, false, false);
              }
            });
  }