Class JobKeyLedger

java.lang.Object
org.apache.juneau.console.views.JobKeyLedger

public final class JobKeyLedger extends Object
The stock "record the minted key" store for row-bound job keys: issues an IdempotencyKey bound to (action, targetId[, principal]), and verifies a submitted key value against that recorded binding.

IdempotencyKey only binds; its consumer records what it minted. This ledger is that record for the row-job case: a key endpoint calls issue(String, String, String) and answers response(IdempotencyKey), and the submit endpoint calls verify(String, String, String, String) (usually through RowJobSubmit.verify(JobKeyLedger, String, String)).

Rules
  • One refusal for every miss. Unknown, expired, evicted and mismatched keys all verify empty, and the caller answers all of them with REFUSAL_CODE, so the answer is no oracle for "this value exists for another row".
  • Spent after first use. On the first successful AsyncJobRegistry.tryCreate(IdempotencyKey) the endpoint calls claim(IdempotencyKey, String). A later verify returns the JobKeyLedger.Grant with that job id, and the endpoint replays the job's ref while the registry still has it, or answers SPENT_CODE — never a second tryCreate, so a replay after the registry's retention cannot start a second job.
  • Bounded per principal. A principal holds at most maxPerPrincipal unspent keys per action; one more evicts that principal's oldest. maxEntries is a global backstop (oldest first). Without auth, every caller is one shared principal.
  • Same actor on both endpoints. Resolve the principal the same way on the key endpoint and on submit, or verify fails.

In-memory and single-process, like AsyncJobRegistry. Safe for concurrent use.

Example:

private final JobKeyLedger jobKeys = JobKeyLedger.create(); @RestPost(path="/species/{id}/key") public Map<String,Object> key(RestRequest req, @Path("id") String id) { return JobKeyLedger.response(jobKeys.issue("restock-species", id, actor(req))); }

See Also:
Since:
10.0.0
  • Field Details

  • Method Details

    • create

      public static JobKeyLedger create()
      Creates a ledger with the default limits.
      Returns:
      A new ledger.
    • ttl

      public JobKeyLedger ttl(Duration value)
      Parameters:
      value - How long an issued key stays verifiable. Must be positive.
      Returns:
      This object.
    • maxEntries

      public JobKeyLedger maxEntries(int value)
      Parameters:
      value - The global entry cap. Must be positive.
      Returns:
      This object.
    • maxPerPrincipal

      public JobKeyLedger maxPerPrincipal(int value)
      Parameters:
      value - The per-principal, per-action cap on unspent keys. Must be positive.
      Returns:
      This object.
    • clock

      public JobKeyLedger clock(Clock value)
      Parameters:
      value - The clock, for tests.
      Returns:
      This object.
    • issue

      public IdempotencyKey issue(String action, String targetId)
      Mints and records a key bound to (action, targetId) with no principal.
      Parameters:
      action - The action id. Must not be null or blank.
      targetId - The row id. Must not be null or blank.
      Returns:
      The new key.
      Throws:
      IllegalArgumentException - If an argument is null or blank.
    • issue

      public IdempotencyKey issue(String action, String targetId, String principal)
      Mints and records a key bound to (action, targetId) and to the actor.
      Parameters:
      action - The action id. Must not be null or blank.
      targetId - The row id. Must not be null or blank.
      principal - The actor. Must not be null or blank.
      Returns:
      The new key.
      Throws:
      IllegalArgumentException - If an argument is null or blank.
    • verify

      public Optional<JobKeyLedger.Grant> verify(String value, String action, String targetId)
      Verifies a submitted key against a binding with no principal.
      Parameters:
      value - The submitted key value. Can be null.
      action - The action the submit is for. Can be null.
      targetId - The row the submit is for. Can be null.
      Returns:
      The grant, or empty for every kind of miss.
    • verify

      public Optional<JobKeyLedger.Grant> verify(String value, String action, String targetId, String principal)
      Verifies a submitted key against a binding and an actor.
      Parameters:
      value - The submitted key value. Can be null.
      action - The action the submit is for. Can be null.
      targetId - The row the submit is for. Can be null.
      principal - The actor. Can be null (then only a key issued without a principal verifies).
      Returns:
      The grant, or empty for every kind of miss.
    • claim

      public void claim(IdempotencyKey key, String jobId)
      Records the job a key started, so a later verify carries it and the key can never start a second one.

      Idempotent for the same job id. A key that is no longer recorded is ignored.

      Parameters:
      key - The verified key. Must not be null.
      jobId - The job it started. Must not be null or blank.
      Throws:
      IllegalArgumentException - If an argument is null or blank.
      IllegalStateException - If the key already started a different job.
    • size

      public int size()
      The number of recorded keys, for tests and diagnostics.
      Returns:
      The entry count after a sweep.
    • response

      public static Map<String,Object> response(IdempotencyKey key)
      The key endpoint's response body: {contractVersion, action, targetId, idempotencyKey}.
      Parameters:
      key - The issued key. Must not be null.
      Returns:
      An ordered map.
    • toString

      public String toString()
      Overrides:
      toString in class Object