Class UsageLockValidator
- All Implemented Interfaces:
CommandValidator,PlayerCacheSaver
Acquire-then-execute (D-02, GEN-09, @since 6.3.0): acquisition is no longer a
separate step called by field from BaseCommandExecutor.executeCommand. It happens
inside validate(CommandContext) itself -- "acquire-as-you-validate" -- so that on
the synchronous dispatch path there is no scheduling point between deciding the lock is free
and taking it. A failed acquisition surfaces as an ordinary CommandValidator.ValidationResult.failure(java.lang.String)
through the normal validation-rejection path; the mapped method is never invoked. Release
happens in onComplete(CommandContext, boolean), driven by the validator chain that
actually ran this validator (see CommandValidator.onComplete(CommandContext, boolean)) --
never called twice, and never called for an invocation whose acquisition failed.
- Since:
- 6.2.0
- Version:
- 2.0.0
- Author:
- wisdomme
-
Nested Class Summary
Nested classes/interfaces inherited from interface com.ultikits.ultitools.abstracts.command.validation.CommandValidator
CommandValidator.ValidationResult -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final intprivate booleanTrue once this instance has registeredsenderLocks/serverLockswith the livePlayerCacheManagerfor quit-based sweeping (GEN-08, D-03).Locks per sender: player UUID -> set of locked method keysServer-wide locks: method key -> locking player UUID -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionbooleanacquireLock(CommandContext context) Acquires a lock for command execution.voidClears all locks.voidclearPlayerLocks(UUID playerId) Clears all locks for a player.private voidAttempts lazy first-use registration of this instance with the livePlayerCacheManagersingleton.getName()Gets the name of this validator for debugging and logging purposes.intgetOrder()Gets the order of this validator.booleanChecks if a specific method is locked for a player.voidonComplete(CommandContext context, boolean commandSucceeded) Post-action hook that releases the lock acquired byvalidate(CommandContext)for this invocation.voidreleaseLock(CommandContext context) Releases a lock after command execution.private static UsageLimitresolveLimit(Method method, Class<?> executorClass) Resolves the effective@UsageLimitformethod: the method's own declaration, falling back to a class-level one on the CONCRETE executor class dispatching this command, falling back to a class-level one on the method's declaring class -- most-derived-wins, viaReflectionUtil.resolveMethodOrClassAnnotation(Method, Class, Class).voidsavePlayerData(UUID playerId) PlayerCacheSaverhook: fired byPlayerCacheManager.onPlayerQuit(UUID)("the quit sweep") for the quitting player -- before the generic@PlayerCachefield sweep removes the (by then already-empty)senderLocks/serverLocksentries.validate(CommandContext context) Validates -- and, per the acquire-then-execute contract on this class, ATTEMPTS TO ACQUIRE -- the lock for this invocation.Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface com.ultikits.ultitools.abstracts.command.validation.CommandValidator
shouldValidate
-
Field Details
-
ORDER
private static final int ORDER- See Also:
-
senderLocks
Locks per sender: player UUID -> set of locked method keyssaveBeforeRemove = truesosavePlayerData(UUID)-- which delegates to the pre-existingclearPlayerLocks(UUID), clearing BOTH this field andserverLocksin one call -- fires exactly once per quit (GEN-08, D-03).serverLocksdeliberately does NOT also carrysaveBeforeRemove = true: doing so would firesavePlayerData(UUID)a second, redundant time per quit. -
serverLocks
Server-wide locks: method key -> locking player UUID -
playerCacheRegistered
private volatile boolean playerCacheRegisteredTrue once this instance has registeredsenderLocks/serverLockswith the livePlayerCacheManagerfor quit-based sweeping (GEN-08, D-03). Set lazily fromvalidate(CommandContext)rather than the constructor, mirroringCooldownValidator's identical field of the same name and rationale: a barenew UsageLockValidator()must never attempt contact with a core plugin that may not exist yet, and a failed attempt is retried on the next call rather than permanently abandoned.
-
-
Constructor Details
-
UsageLockValidator
public UsageLockValidator()
-
-
Method Details
-
validate
Validates -- and, per the acquire-then-execute contract on this class, ATTEMPTS TO ACQUIRE -- the lock for this invocation. Delegates entirely toacquireLock(CommandContext): a successful acquisition is a successful validation; a failed acquisition is reported as an ordinary validation failure carrying the scope-appropriate i18n key.- Specified by:
validatein interfaceCommandValidator- Parameters:
context- the command context- Returns:
- the validation result
-
onComplete
Post-action hook that releases the lock acquired byvalidate(CommandContext)for this invocation. Delegates toreleaseLock(CommandContext)and is invoked only by a chain that actually ran this validator for the current dispatch -- seeCommandValidator.onComplete(CommandContext, boolean). An invocation whose acquisition failed never reaches this hook (it is absent from the chain's passed-validator list), so there is nothing here to release on that path.- Specified by:
onCompletein interfaceCommandValidator- Parameters:
context- the command contextcommandSucceeded- ignored -- the lock releases whether the mapped method succeeded or threw- Since:
- 6.3.0
-
ensurePlayerCacheRegistered
private void ensurePlayerCacheRegistered()Attempts lazy first-use registration of this instance with the livePlayerCacheManagersingleton. Safe to call unconditionally on everyvalidate(CommandContext)invocation: a no-op onceplayerCacheRegisteredis true, and a cheap, safely-no-op-on-failure retry otherwise (see that field's javadoc). -
savePlayerData
PlayerCacheSaverhook: fired byPlayerCacheManager.onPlayerQuit(UUID)("the quit sweep") for the quitting player -- before the generic@PlayerCachefield sweep removes the (by then already-empty)senderLocks/serverLocksentries. Delegates to the pre-existingclearPlayerLocks(UUID)rather than re-deriving its predicate -- the SAME predicatePlayerCacheManager's own value-side sweep branch was built from -- giving that previously zero-caller method a real, quit-path-reached production call site (GEN-08). OnlysenderLockscarriessaveBeforeRemove = true, so this fires exactly once per quit despite clearing both maps.- Specified by:
savePlayerDatain interfacePlayerCacheSaver- Parameters:
playerId- the UUID of the player quitting- Since:
- 6.3.0
-
acquireLock
Acquires a lock for command execution. Should be called before executing the command. As of 6.3.0 this is also the methodvalidate(CommandContext)itself calls -- see the class-level acquire-then-execute note.- Parameters:
context- the command context- Returns:
- true if lock was acquired, false if already locked
-
releaseLock
Releases a lock after command execution. Should be called after command execution completes (success or failure). As of 6.3.0 this is also the methodonComplete(CommandContext, boolean)calls -- see the class-level acquire-then-execute note.- Parameters:
context- the command context
-
resolveLimit
Resolves the effective@UsageLimitformethod: the method's own declaration, falling back to a class-level one on the CONCRETE executor class dispatching this command, falling back to a class-level one on the method's declaring class -- most-derived-wins, viaReflectionUtil.resolveMethodOrClassAnnotation(Method, Class, Class). This is the SAME resolutionPluginManager's load-time refusal treats as satisfying the contract (SILENT-11 / D-01 follow-up, WR-02 / 05-REVIEW.md fix): a class-level@UsageLimitthat passes the load-time check -- whether declared on a shared abstract base or on the concrete executor class itself -- now actually locks every inherited mapping that does not declare its own.- Parameters:
method- the matched command mapping method, ornullexecutorClass- the concrete executor class dispatching this command (WR-02, 05-REVIEW.md), ornullwhen unavailable -- falls back to the pre-WR-02, declaring-class-only resolution in that case- Returns:
- the resolved annotation, or
nullwhenmethodisnullor neither the method,executorClass, nor its declaring class carries one - Since:
- 6.3.0
-
clearPlayerLocks
Clears all locks for a player. Useful when a player disconnects.- Parameters:
playerId- the player's UUID
-
clearAllLocks
public void clearAllLocks()Clears all locks. -
isLocked
Checks if a specific method is locked for a player.- Parameters:
playerId- the player's UUIDmethodKey- the method key- Returns:
- true if locked
-
getOrder
public int getOrder()Description copied from interface:CommandValidatorGets the order of this validator. Lower values are executed first.- Specified by:
getOrderin interfaceCommandValidator- Returns:
- the order value
-
getName
Description copied from interface:CommandValidatorGets the name of this validator for debugging and logging purposes.- Specified by:
getNamein interfaceCommandValidator- Returns:
- the validator name
-