Class ActingIdentity

java.lang.Object
ubic.gemma.core.security.util.ActingIdentity

public final class ActingIdentity extends Object
The curator an action is being taken FOR, for the duration of one call.

Why this is not a parameter

The audit row is written by AuditTrailServiceImpl deep inside the commit's transaction, reached through an @Audited aspect on a method — applyDesignChange(ee, proposed) — that has no argument for it and should not grow one. Threading the name from the REST layer to the audit writer would mean a new parameter on every service method between them, on every audited path, to carry something almost every caller leaves null.

So it is scoped to the call instead, and read at exactly one place: AuditTrailServiceImpl.createAuditEvent.

🛑 It must be cleared

Threads are pooled. A name left behind is attributed to the next request that lands on the same thread, which is a false entry in the permanent record of who did what — worse than no entry. scope(String) returns an AutoCloseable so the only correct usage is the one that cleans up:

try ( ActingIdentity.Scope ignored = ActingIdentity.scope( actingAs ) ) {
    ...
}

Deliberately NOT inherited by child threads. Work handed to an executor is attributed to the credential that ran it, which is the honest answer: nobody asked a curator about it.

  • Method Details

    • get

      @Nullable public static String get()
      Returns:
      the curator the current call is acting for, or null — which is the ordinary case and means the authenticated principal is the actor.
    • scope

      public static ActingIdentity.Scope scope(@Nullable String onBehalfOf)
      Bind onBehalfOf for the current thread until the returned scope is closed. A null or blank name binds nothing, so a caller does not have to branch.