WorkflowSessionException.java

package org.hammer.audio.workflow.collaboration;

import java.io.Serial;
import java.util.Objects;

/** Typed application error for workflow-session lifecycle and command failures. */
public class WorkflowSessionException extends RuntimeException {

  @Serial private static final long serialVersionUID = 1L;

  /** Stable error codes independent of HTTP or any other transport. */
  public enum Code {
    SESSION_ALREADY_EXISTS,
    SESSION_NOT_FOUND,
    PRIVATE_WORKSPACE_ACCESS_DENIED,
    ACTOR_METADATA_MISMATCH,
    ACTOR_NOT_JOINED,
    SESSION_MODE_MISMATCH,
    SESSION_CLOSE_FORBIDDEN,
    DUPLICATE_OPERATION_ID,
    INVALID_OPERATION_AUTHOR,
    UNDO_TARGET_REQUIRED,
    UNDO_TARGET_NOT_FOUND,
    OPERATION_NOT_UNDOABLE,
    UNDO_PREVIEW_REQUIRED,
    UNDO_PREVIEW_STALE,
    UNDO_CONFLICT,
    REDO_TARGET_NOT_FOUND,
    REDO_TARGET_INVALID,
    REDO_ALREADY_APPLIED
  }

  private final Code errorCode;
  private final String relatedSessionId;

  /** Creates a typed session exception. */
  public WorkflowSessionException(Code code, String sessionId, String message) {
    super(validateBeforeConstruction(code, message));
    this.errorCode = code;
    this.relatedSessionId = sessionId;
  }

  /** Returns the stable transport-independent error code. */
  public Code code() {
    return errorCode;
  }

  /** Returns the related session id, or {@code null} when none is available. */
  public String sessionId() {
    return relatedSessionId;
  }

  private static String validateBeforeConstruction(Code code, String message) {
    Objects.requireNonNull(code, "code");
    return Objects.requireNonNull(message, "message");
  }
}