All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nthportal.concurrent.CancellableTask.scala Maven / Gradle / Ivy

/*
 * This file is adapted and modified from Stratio/common-utils
 * (https://github.com/Stratio/common-utils/blob/b9195e3a2b206bb65bf61b412371cf07858d5450/src/main/scala/com/stratio/common/utils/concurrent/Cancellable.scala),
 * as well as from this Stack Overflow answer
 * (https://stackoverflow.com/a/39986418/5101123).
 *
 * The original implementation is licenced under the Apache License, Version 2.0,
 * and the original license is reproduced below. This file is licensed under the
 * Apache License, Version 2.0 as well.
 */

/*
 * ---- ORIGINAL LICENSE AND COPYRIGHT INFORMATION ----
 *
 * Copyright (C) 2015 Stratio (http://stratio.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.nthportal.concurrent

import java.util.concurrent.{Callable, FutureTask}

import scala.concurrent._
import scala.util.Try

/**
  * An asynchronously executed task which can be cancelled
  * before or during its execution.
  *
  * @param body the task to execute
  * @param ec   the context in which to execute the task
  * @tparam T the return type of `body`
  */
final class CancellableTask[T] private(body: => T, ec: ExecutionContext) {
  private val promise = Promise[T]()

  private val task = new FutureTask[T](new Callable[T] {override def call() = body}) {
    override def done() = promise complete {
      Try(get) recover {
        case t: ExecutionException => t.getCause match {
          case e: CancellationException => throw new OtherCancellationException(e)
          case e: OtherCancellationException => throw new OtherCancellationException(e)
          case e => throw e
        }
      }
    }
  }
  ec.execute(task)

  /**
    * Returns a [[Future]] which will contain the result of this task
    * when it is completed.
    *
    * @return a Future which will contain the result of this task
    *         when it is completed
    */
  def future: Future[T] = promise.future

  /**
    * Attempts to cancel this task.
    *
    * This method behaves the same as
    * [[java.util.concurrent.FutureTask `java.util.concurrent.FutureTask.cancel()`]].
    * See its documentation for more details.
    *
    * @param mayInterruptIfRunning whether or not to attempt to cancel the task
    *                              if it has already been started
    * @return `true` if the task was cancelled by this invocation; `false` otherwise
    */
  def cancel(mayInterruptIfRunning: Boolean): Boolean = task.cancel(mayInterruptIfRunning)

  /**
    * Returns `true` if the task was cancelled before completing; `false` otherwise.
    *
    * If this method returns `true`, then [[future]] will fail with a
    * [[CancellationException]].
    *
    * @return `true` if the task was cancelled before completing; `false` otherwise
    */
  def isCancelled: Boolean = task.isCancelled
}

object CancellableTask {
  /**
    * Creates a cancellable task which will be executed asynchronously.
    *
    * @param body the task to execute
    * @param ec the context in which to execute the task
    * @tparam T the return type of `body`
    * @return a cancellable task with the specified body
    */
  def apply[T](body: => T)(implicit ec: ExecutionContext): CancellableTask[T] = new CancellableTask(body, ec)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy