/**
   * Ausfuehrung der Evaluierung. Jeder Ausdruck wird ueber die Verbindung ausgewertet und das
   * Ergebnis der Evaluierung wird dem {@link IBackgroundEvaluationListener} mitgeteilt.
   *
   * @param monitor - der ProgressMonitor
   * @see IBackgroundEvaluationListener
   * @sse {@link AbstractJob#run0(IProgressMonitor)}
   */
  @Override
  @SuppressWarnings("NP") // Rueckgabe von non-null Wert wird über Methoden-Contract geregelt
  protected IStatus run0(final IProgressMonitor monitor) throws Exception {
    monitor.subTask("Waiting for connection");
    acquireLock();

    ensureConnected(fConnection);
    callPrepare(fForms.size() > 1);

    monitor.beginTask(fJobName, (fForms.size() + 1) * 1000);

    if (monitor.isCanceled()) {
      return Status.CANCEL_STATUS;
    }

    for (int i = 0, n = fForms.size(); i < n; i++) {

      PackageBoundForm form = fForms.get(i);
      monitor.subTask("Starting evaluation " + i + "/" + fForms.size());
      IEvaluation eval = fConnection.getEvaluation();

      eval.evalStart(form.getPackage(), form.getForm());

      // Output Lesen
      readAllOutput(monitor);

      monitor.subTask("Reading result");
      IResult evalResult = eval.evalResult();

      boolean more = i != n - 1;
      IRestartSelection selection = callFormEvaluated(evalResult, more);

      monitor.worked(1000);

      if (evalResult.getTyp() == TResult.SUCCESS) { // Ergebnis ok
        continue; // alles ok mit ergebnis, mit naechstem weitermachen wenn vorhanden
      } else if (evalResult.getTyp()
          == TResult.READ_ERROR) { // Read error, es darf kein abort gesendet werden
        break;
      } else if (selection != null && selection.isAborted()) {
        abort(); // Ein Fehler, kann nur EVAL_ERROR sein, wurde abgebrochen
        break;
      } else { // EVAL_ERROR und es wurde ein Restart gewaehlt, bzw. war verfuegbar
        boolean abort = restart(monitor, selection, more); // eintritt rekursiver restart
        if (abort) { // restart abgebrochen
          abort(); // abort senden
          break; // und (bulk-)eval komplette beenden
        }
        continue; // restart war erfolgreich -> weiter mit naechstem im bulk
      }
    }

    return new Status(IStatus.OK, LispPluginActivator.ID, IStatus.OK, "Evaluation succeeded", null);
  }
  /**
   * Fuehrt einen Restart am Server durch.
   *
   * @param monitor
   * @param selection
   * @param more
   * @return true wenn abbruch
   * @throws ConnectionException
   */
  private boolean restart(
      final IProgressMonitor monitor, final IRestartSelection selection, final boolean more)
      throws ConnectionException {
    monitor.subTask("Invoking restart");
    fConnection
        .getProtocolWriter()
        .writeInvokeRestart(selection.getRestart(), selection.getParameter());
    readAllOutput(monitor);
    monitor.subTask("Reading restart result");
    IResult result = fConnection.getEvaluation().evalResult();
    IRestartSelection restartSelection = callFormEvaluated(result, more);

    if (restartSelection == null) {
      return false;
    } else if (restartSelection.isAborted()) {
      return true;
    } else {
      // rekursiver restart
      return restart(monitor, restartSelection, more);
    }
  }