Package groovy.concurrent

# Interface ActorContext<T>

Type Parameters:
  `T` - the actor's message type

public interface ActorContext<T>
Context handle passed to context-aware actor handlers. Provides access to the executing actor itself and to the per-dispatch capabilities needed to express FSM-style actors: behavior swaps via `become(...)`, message deferral via `stash()` / `unstashAll()`, and timed self-sends via `scheduleOnce(...)` / `scheduleAtFixedRate(...)`.

A context is scoped to a single actor and is only valid for use during a handler invocation (including a context-aware `onError` callback). Calls to its mutating methods from outside that window — for example from a captured reference invoked on another thread — throw `IllegalStateException`.

Since:
  6.0.0
See Also:
  - `Actor`

- ## Method Summary

  Modifier and Type
  Method
  Description
  `default <R> void`
  `become(ReactorHandler<T,R> newHandler)`
  Replaces the handler used to process subsequent messages on a reactor actor.
  `default <S> void`
  `become(StatefulHandler<S,T> newHandler)`
  Replaces the handler used to process subsequent messages on a stateful actor.
  `default Cancellable`
  `scheduleAtFixedRate(T message, Duration initialDelay, Duration interval)`
  Schedules a recurring self-send: the given message is delivered to this actor starting after `initialDelay`, then again every `interval` thereafter (fixed-rate).
  `default Cancellable`
  `scheduleOnce(T message, Duration delay)`
  Schedules a one-shot self-send: the given message is delivered to this actor after the given delay, via the same dispatch path as `Actor.send(Object)` (mailbox bound respected, `onError` fires on handler failure, etc.).
  `Actor<T>`
  `self()`
  Returns the actor whose handler is currently executing.
  `default void`
  `stash()`
  Defers the message currently being processed.
  `default void`
  `unstashAll()`
  Re-injects all stashed messages at the head of the mailbox in the order they were originally stashed (FIFO).

- ## Method Details

  - ### self

    Actor<T> self()
    Returns the actor whose handler is currently executing.

  - ### become

    default <R> void become(ReactorHandler<T,R> newHandler)
    Replaces the handler used to process subsequent messages on a reactor actor. The swap takes effect on the next message — the current handler invocation completes normally, including binding any `sendAndGet` reply and firing `onError` on failure.

    The new handler may declare a different reply type than the original; `sendAndGet` callers receive the new handler's return value.

    Messages already queued at the moment of the swap, and messages sent by other threads that have not yet observed the swap, are dispatched to the new handler. The new handler is responsible for tolerating any message its predecessor could have received — typically by including a default branch that ignores or rejects unexpected messages, or by deferring them with `stash()` for later replay.

    Type Parameters:
      `R` - the new reactor's reply type
    Parameters:
      `newHandler` - the replacement reactor handler
    Throws:
      `UnsupportedOperationException` - if this actor is stateful, or if this `ActorContext` implementation does not support behavior swaps
      `IllegalStateException` - if called outside a handler dispatch or from a thread other than the actor's worker thread
      `NullPointerException` - if `newHandler` is null
    Since:
      6.0.0

  - ### become

    default <S> void become(StatefulHandler<S,T> newHandler)
    Replaces the handler used to process subsequent messages on a stateful actor. The current state value is preserved verbatim and passed unchanged to the new handler. The swap takes effect on the next message.

    The state type `S` is unchecked at the swap site: if the new handler's expected state type is incompatible with the actor's current state, a `ClassCastException` is thrown when the next message is dispatched.

    Type Parameters:
      `S` - the state type expected by the new handler
    Parameters:
      `newHandler` - the replacement stateful handler
    Throws:
      `UnsupportedOperationException` - if this actor is a reactor, or if this `ActorContext` implementation does not support behavior swaps
      `IllegalStateException` - if called outside a handler dispatch or from a thread other than the actor's worker thread
      `NullPointerException` - if `newHandler` is null
    Since:
      6.0.0

  - ### stash

    default void stash()
    Defers the message currently being processed. The message is moved out of the dispatch path: any `sendAndGet` reply remains unbound, any state change computed by the current handler is discarded, and the message is re-delivered when `unstashAll()` is later called.

    Calling `stash()` more than once during a single handler invocation is idempotent — the message is stashed once. If the handler subsequently throws, the stash is rolled back and the failure is reported normally (reply bound to error, `onError` fires). A context-aware `onError` callback may itself call `stash()` to defer the failed message for later retry.

    Stashed messages do not count against the configured mailbox bound — the bound applies to the queue of pending sends, not to messages held in the stash.

    Warning — the stash buffer is unbounded by default. An actor that stashes messages from a source whose volume you do not control (network input, external clients, untrusted callers) can grow the stash without limit and exhaust the JVM heap if the phase transition that would call `unstashAll()` never arrives. For any such actor, configure a bound and overflow policy at construction time via `ActorOptions.withStashBound(int, ActorOptions.StashOverflow)`. The three policies are `FAIL` (this method throws), `DROP_OLDEST` (evicts the oldest stashed message, binding its reply to `IllegalStateException`), and `REJECT` (binds the current message's reply to `IllegalStateException` and does not stash it).

    If `Actor.stop()` is invoked while messages are stashed, the stashed messages are rejected: any `sendAndGet` reply is bound to an `IllegalStateException` and fire-and-forget stashed messages are discarded.

    Throws:
      `IllegalStateException` - if called outside a handler dispatch or from a thread other than the actor's worker thread
      `UnsupportedOperationException` - if this `ActorContext` implementation does not support stash
    Since:
      6.0.0

  - ### unstashAll

    default void unstashAll()
    Re-injects all stashed messages at the head of the mailbox in the order they were originally stashed (FIFO). Subsequent dispatches will see the unstashed messages before any messages that other senders have queued in the meantime.

    No-op if no messages are stashed.

    Throws:
      `IllegalStateException` - if called outside a handler dispatch or from a thread other than the actor's worker thread
      `UnsupportedOperationException` - if this `ActorContext` implementation does not support stash
    Since:
      6.0.0

  - ### scheduleOnce

    default Cancellable scheduleOnce(T message, Duration delay)
    Schedules a one-shot self-send: the given message is delivered to this actor after the given delay, via the same dispatch path as `Actor.send(Object)` (mailbox bound respected, `onError` fires on handler failure, etc.).

    The returned `Cancellable` can be used to call off the send before it fires. On `Actor.stop()`, all outstanding scheduled timers (one-shot and recurring) created via this context are cancelled automatically.

    Timer firings race with the actor's lifecycle: a send that arrives after the actor has stopped is silently dropped (the implementation catches the `IllegalStateException` that `send` would throw). Combining a bounded mailbox using `ActorOptions.Overflow.BLOCK` with timers is discouraged: each timer firing offloads its `send` to the shared async executor, so the scheduler thread itself never blocks, but a full mailbox will then tie up an executor thread until space frees, and enough such timers can exhaust the shared pool. Prefer `FAIL` or `DROP_NEWEST` for actors that schedule their own messages.

    Parameters:
      `message` - the message to deliver
      `delay` - how long to wait before delivering
    Returns:
      a handle for cancelling the scheduled send
    Throws:
      `IllegalStateException` - if called outside a handler dispatch or from a thread other than the actor's worker thread
      `NullPointerException` - if `message` or `delay` is null
      `UnsupportedOperationException` - if this `ActorContext` implementation does not support scheduling
    Since:
      6.0.0

  - ### scheduleAtFixedRate

    default Cancellable scheduleAtFixedRate(T message, Duration initialDelay, Duration interval)
    Schedules a recurring self-send: the given message is delivered to this actor starting after `initialDelay`, then again every `interval` thereafter (fixed-rate). Cancellation stops further firings; an already-dispatched message in the mailbox is unaffected.

    Same lifecycle and bounded-mailbox caveats as `scheduleOnce(Object, Duration)` apply.

    Parameters:
      `message` - the message to deliver
      `initialDelay` - the wait before the first delivery
      `interval` - the wait between successive deliveries
    Returns:
      a handle for cancelling further firings
    Throws:
      `IllegalStateException` - if called outside a handler dispatch or from a thread other than the actor's worker thread
      `NullPointerException` - if any argument is null
      `UnsupportedOperationException` - if this `ActorContext` implementation does not support scheduling
    Since:
      6.0.0