protected void outputMessage(ConsoleView consoleView) {
   if (StringUtil.isNotEmpty(getComment())) {
     printComment(consoleView);
     consoleView.print(
         "-----------------------------------------------------\n",
         ConsoleViewContentType.SYSTEM_OUTPUT);
   }
   consoleView.print(myStacktrace, ConsoleViewContentType.ERROR_OUTPUT);
   consoleView.print("\n", ConsoleViewContentType.NORMAL_OUTPUT);
 }
  @Override
  @NotNull
  public ExecutionResult execute(
      @NotNull final Executor executor, @NotNull final ProgramRunner runner)
      throws ExecutionException {

    log.debug("execute: about to call startProcess");

    OSProcessHandler processHandler = startProcess();

    ConsoleView consoleView =
        TextConsoleBuilderFactory.getInstance()
            .createBuilder(this.getEnvironment().getProject())
            .getConsole();

    consoleView.print("Starting substeps test...", ConsoleViewContentType.NORMAL_OUTPUT);

    SubstepsRunConfiguration runConfig =
        (SubstepsRunConfiguration) this.getEnvironment().getRunProfile();

    boolean substepsServerLogsToConsole = true;
    if (substepsServerLogsToConsole) {
      consoleView.attachToProcess(processHandler);
    } else {

      Semaphore consoleSemaphore = new Semaphore(1, true);
      InputStreamConsumer consumer =
          new InputStreamConsumer(
              processHandler.getProcess().getInputStream(),
              log,
              false,
              consoleView,
              consoleSemaphore);
      final Thread t = new Thread(consumer);
      t.start();

      InputStreamConsumer errorConsumer =
          new InputStreamConsumer(
              processHandler.getProcess().getErrorStream(),
              log,
              true,
              consoleView,
              consoleSemaphore);
      final Thread t2 = new Thread(errorConsumer);
      t2.start();
    }
    processHandler.startNotify();
    //
    //
    //
    //        boolean exceptionThrown = false;
    //        try {
    //            this.log.info("waiting for process to start...");
    //            processStarted.await(30, TimeUnit.SECONDS);
    //
    //            this.log.info("waited..");
    //
    //            if (!processStartedOk.get()) {
    //                exceptionThrown = true;
    //                throw new ExecutionException("Unable to launch VM process");
    //            }
    //
    //            this.log.info("process started");
    //        } catch (final InterruptedException e) {
    //
    //            e.printStackTrace();
    //        }

    //        try {
    //            Thread.currentThread().sleep(5000);
    //        } catch (InterruptedException e) {
    //            e.printStackTrace();
    //        }

    log.debug("startProcess called");

    SubstepsRunnerConfigurationModel model = runConfig.getModel();

    boolean actualRunnerStarted = false;

    // TODO - this is a bit messy, concerns not well separated
    SubstepsJMXClient jmxClient = null;
    try {
      jmxClient = new SubstepsJMXClient();

      if (!jmxClient.init(jmxPort)) {
        log.error("jmx init failed");
        processHandler.destroyProcess();
        return new DefaultExecutionResult();
      }

      SubstepsExecutionConfig substepsExecutionConfig = new SubstepsExecutionConfig();

      substepsExecutionConfig.setFeatureFile(model.getPathToFeature());

      String[] stepImplsArray =
          model
              .getStepImplentationClassNames(); // .toArray(new
                                                // String[model.getStepImplentationClassNames().size()]);

      substepsExecutionConfig.setDescription("Substeps Tests");

      substepsExecutionConfig.setStepImplementationClassNames(stepImplsArray);

      substepsExecutionConfig.setSubStepsFileName(model.getSubStepDefinitionDirectory());

      substepsExecutionConfig.setScenarioName(model.getScenarioName());

      log.debug(
          "SubstepsExecutionConfig details\nFeature: "
              + model.getPathToFeature()
              + "\nsubstep dir: "
              + model.getSubStepDefinitionDirectory()
              + " scenarioName: "
              + model.getScenarioName());

      for (String s : model.getStepImplentationClassNames()) {
        log.debug("step impl classname: " + s);
      }
      /*
      private String description;
      private String tags;
      private String nonFatalTags;
      private String subStepsFileName;
      private boolean strict = true;
      private boolean fastFailParseErrors = true;
      private Properties systemProperties;
      private String[] nonStrictKeywordPrecedence;
      private String[] stepImplementationClassNames;
      private String[] initialisationClass;
      private List<Class<?>> stepImplementationClasses;
      private Class<?>[] initialisationClasses;
      private String[] executionListeners;
           */

      log.debug("preparing config");

      byte[] bytes = jmxClient.prepareExecutionConfigAsBytes(substepsExecutionConfig);

      RootNode rn = getRootNodeFromBytes(bytes);

      log.debug("got root node description: " + rn.getDescription());

      final SubstepsTestProxy unboundOutputRoot = new SubstepsTestProxy(rn);

      final SubstepsConsoleProperties consoleProperties =
          new SubstepsConsoleProperties(runConfig, executor);
      final SubstepsConsoleView substepsConsoleView =
          new SubstepsConsoleView(
              consoleView, consoleProperties, this.getEnvironment(), unboundOutputRoot);

      DefaultExecutionResult execResult =
          new DefaultExecutionResult(
              substepsConsoleView,
              processHandler,
              createActions(substepsConsoleView, processHandler, executor));

      Disposer.register(this.getEnvironment().getProject(), substepsConsoleView);
      substepsConsoleView.initUI();
      substepsConsoleView.attachToProcess(processHandler);
      unboundOutputRoot.setPrinter(substepsConsoleView.getPrinter());
      Disposer.register(substepsConsoleView, unboundOutputRoot);

      SubstepsRunningModel runModel =
          new SubstepsRunningModel(unboundOutputRoot, consoleProperties);

      SubstepsListenersNotifier eventsConsumer = unboundOutputRoot.getEventsConsumer();

      substepsConsoleView.attachToModel(runModel);

      RunningTestTracker.install(runModel);

      log.debug("rootNode result from prepare config: " + rn.getResult().getResult());

      if (rn.getResult().getResult().isFailure()) {

        // bail out early
        unboundOutputRoot.setState(SubstepTestState.FAILED);
        eventsConsumer.onEvent(new StateChangedEvent(unboundOutputRoot));

        jmxClient.shutdown();
        log.debug("shut down done!");

      } else {
        log.debug("config prepared");

        List<SubstepsTestProxy> allTestNodes = unboundOutputRoot.getAllTests();
        Map<Long, SubstepsTestProxy> proxyMap = new HashMap<>();
        for (SubstepsTestProxy proxy : allTestNodes) {
          proxyMap.put(proxy.getExecutionNodeId(), proxy);
        }

        ActualRunner actualRunner =
            new ActualRunner(jmxClient, log, eventsConsumer, proxyMap, unboundOutputRoot);

        new Thread(actualRunner).start();
        actualRunnerStarted = true;
      }

      return execResult;
    } finally {
      if (!actualRunnerStarted && jmxClient != null) {

        // if we've got to the end and not actually kicked off the runner, make sure we shut down.

        jmxClient.shutdown();
      }
    }
  }
 public void printlnSystemMessage(@NotNull String s) {
   myConsole.print(s + "\n", ConsoleViewContentType.SYSTEM_OUTPUT);
 }
    /*
     * (non-Javadoc)
     *
     * @see java.lang.Runnable#run()
     */
    public void run() {

      String line = null;
      try {

        int c;
        StringBuilder buf = new StringBuilder();
        while ((c = this.stderr.read()) != -1) {

          String s = String.valueOf((char) c);
          //                    consoleView.print(s, ConsoleViewContentType.NORMAL_OUTPUT);

          if ((char) c == '\n') {
            line = buf.toString();

            try {
              this.consoleSemaphore.acquire();
              consoleView.print(line + "\n", ConsoleViewContentType.NORMAL_OUTPUT);

            } catch (InterruptedException e) {
              e.printStackTrace();
            } finally {
              this.consoleSemaphore.release();
            }

            buf = new StringBuilder();
            if (isError) {
              log.error("*\t" + line);
            } else {
              log.debug("*\t" + line);
            }
            checkLine(line);

          } else {
            buf.append(s);
          }
        }

        //                this.isr = new InputStreamReader(this.stderr);
        //                this.br = new BufferedReader(this.isr);
        //
        //                log.debug("awaiting input...");
        //
        //                while ((line = this.br.readLine()) != null) {
        //
        //                    consoleView.print(line + "\n", ConsoleViewContentType.NORMAL_OUTPUT);
        //                    // NB. this is not a logger as we don't want to be able to turn
        //                    // this off
        //                    // If the level of logging from the child process is verbose,
        //                    // change the logging level of the spawned process.
        //
        //                    if (isError){
        //                        log.error("*\t" + line);
        //                    }
        //                    else {
        //                        log.debug("*\t" + line);
        //                    }
        //                    checkLine(line);
        //
        //                }
      } catch (final IOException e) {

        e.printStackTrace();
      } finally {
        doFinalCheck();
      }
    }
 @Override
 public void print(@NotNull String s) {
   myConsole.print(s, ConsoleViewContentType.NORMAL_OUTPUT);
 }