package org.jetbrains.bsp.protocol.session

import java.util.concurrent.CompletableFuture

/**
 * JDK's CompletableFuture does not handle cancellation well.
 * When a future overrides a `cancel` method, it is lost
 * when doing transformations like `thenApply` or `thenCompose`.
 *
 * In Java 9, the new CompletableFuture's method was introduced: `newIncompleteFuture`.
 * When using it, the cancel method of the original future will be called event when the
 * `cancel` is done on a transformed one.
 *
 * When we know about CompletableFutures that override `cancel` methods, we should convert them
 * to CancellableFuture before calling methods like `thenCompose`
 *
 * @param original
 */
class CancellableFuture[T](original: CompletableFuture[_]) extends CompletableFuture[T] {
  override def cancel(mayInterruptIfRunning: Boolean): Boolean = {
    original.cancel(mayInterruptIfRunning)
    super.cancel(mayInterruptIfRunning)
  }

  def newIncompleteFuture[U](): CompletableFuture[U] = {
    new CancellableFuture(original)
  }
}

object CancellableFuture {
  def from[T](original: CompletableFuture[T]): CancellableFuture[T] = {
    val result = new CancellableFuture[T](original)
    original.whenComplete{ (value, error) =>
      if (error != null) {
        result.completeExceptionally(error)
      }
      else {
        result.complete(value)
      }
      ()
    }
    result
  }
}

Revert "static factory method replaced with a plain constructor call, newIncompleteFuture commented out until Java 9"
Revert "static factory method replaced with a plain constructor call, newIncompleteFuture commented out until Java 9"

This reverts commit e0c4e0ac5afd29756f5c81782b0d8d4b0e84fae8.

(cherry picked from commit b70fe2c5013bc86b5ca65515ce527335e004b096)
