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

org.opalj.br.analyses.ProgressManagement.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package br
package analyses

/**
 * Enables the management of the progress of a long running computation.
 * Typically a long running progress, such as an analysis, is expected to report
 * progress every 250 to 2000 milliseconds. It should -- however -- check every ~100
 * milliseconds the interrupted status to enable a timely termination.
 *
 * This trait defines a call-back interface that is implemented by some class that
 * runs an analysis and which passes an instance of it to some analysis to report
 * progress.
 *
 * @note   Implementations of this class must be thread safe if the analysis is multi-
 *         threaded.
 * @note   Implementations must handle the case where a step that was started later
 *         finishes earlier than a previous step. In other words, even if the last step
 *         has ended, that does not mean that the analysis as a whole has already finished.
 *         Instead an implementation has to track how many steps have ended to determine
 *         when the whole analysis has ended.
 *
 * @author Michael Eichberg
 * @author Arne Lottmann
 */
trait ProgressManagement {

    /**
     * This method is called by the analysis to report progress.
     *
     * An analysis is allowed to just report `End` events. However, if it
     * reports `Start` events it must also report `End` events and it must use
     * the same id to do so. This enables the correlation of the events. The analysis
     * must never report more than one `Start`/`End` event per step id.
     *
     * If the analysis is interrupted it may either signal (as the very last event)
     * a `Killed` event or an `End` event if the analysis completed normally.
     *
     * @param  step The step/id of the event. The first event reported by the analysis
     *         has to use the number "1". The step id of the `Killed` event is "-1".
     * @param  message An optional message. Typically used in combination with `Start`
     *         events.
     */
    def progress(step: Int, event: ProgressEvent, message: Option[String]): Unit

    final def start(step: Int, message: String): Unit = {
        progress(step, ProgressEvents.Start, Some(message))
    }

    final def end(step: Int): Unit = progress(step, ProgressEvents.End, None)

    final def end(step: Int, message: String): Unit = end(step, Some(message))

    final def end(step: Int, message: Option[String]): Unit = {
        progress(step, ProgressEvents.End, message)
    }

    /**
     * A convenience method to execute one analysis step. If executing the step
     * takes longer you have to call `isInterrupted` to check the interrupt status.
     */
    final def step[T](
        step:         Int,
        startMessage: String
    )(
        f: => (T, Option[String])
    ): T = {
        start(step, startMessage)
        val (t, endMessage) = try {
            f
        } catch {
            case t: Throwable => end(step, "failed: "+t.getMessage); throw t
        }
        end(step, endMessage)
        t
    }

    /**
     * This method is called by the analysis method to check whether the analysis should be aborted.
     * The analysis will abort the computation if this method returns `true`.
     */
    def isInterrupted(): Boolean

}

/**
 * Factory for a function to create a default progress management object that
 * basically does not track the progress.
 *
 * @author Michael Eichberg
 */
object ProgressManagement {

    val None: Int => ProgressManagement = maxSteps => new ProgressManagement {

        final override def progress(step: Int, event: ProgressEvent, msg: Option[String]): Unit = {}

        final override def isInterrupted(): Boolean = false

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy