PreparableKey
Marks an interface as a PrepareKey for optimistic concurrency control and resource reservation.
PrepareKey interfaces define operations for preparing, committing, and rolling back changes to shared resources in a transactional manner. This annotation enables the framework to automatically generate proxy implementations that handle the complete prepare-commit-rollback lifecycle with built-in error handling and transaction management.
The annotated interface must extend PrepareKey<T> where T is the value type being prepared. The framework creates dynamic proxy instances that delegate to underlying PrepareKey implementations while providing additional capabilities such as:
Automatic transaction management
Error handling and rollback on failures
Resource cleanup on exceptions
Lifecycle management for prepared values
Prepare-Commit-Rollback Lifecycle
Prepare: Reserve or validate the resource before making changes
Execute: Perform the business logic within the prepared context
Commit: Confirm the changes if execution succeeds
Rollback: Release/cancel the preparation if execution fails
Thread Safety
PrepareKey implementations should be thread-safe as they may be used concurrently across multiple requests. The framework handles synchronization through the proxy layer.
Error Handling
If an exception occurs during the usingPrepare block, the framework automatically:
Calls
rollback()to release prepared resourcesPropagates the original exception to the caller
Ensures cleanup happens even if rollback fails
Since
1.0.0
Parameters
Optional custom name for the prepare key. If empty, the framework will derive the name from the interface's simple class name. The name is used to identify and configure the underlying PrepareKey implementation. Type: String Default: "" (empty string)
See also
for the base interface defining prepare operations
for proxy creation details
for the prepared value container
Throws
if the annotated class does not extend PrepareKey
if proxy creation fails due to configuration issues
Example usage:
@PreparableKey("user-username")
interface UserUsernamePrepareKey : PrepareKey<String> {
// Interface can declare additional prepare-related methods
fun validateUsername(username: String): Boolean
}
// Usage in service with automatic lifecycle management
@Service
class UserService(
private val usernameKey: UserUsernamePrepareKey
) {
fun changeUsername(userId: String, newUsername: String) {
// Framework automatically handles prepare/commit/rollback
usernameKey.usingPrepare(newUsername) {
// This block executes within prepared context
require(usernameKey.validateUsername(newUsername)) {
"Username already taken"
}
// Perform the actual username change
userRepository.updateUsername(userId, newUsername)
// If successful, framework calls commit()
// If exception thrown, framework calls rollback()
}
}
fun registerUser(email: String, username: String): UserId {
return usernameKey.usingPrepare(username) {
val userId = userRepository.createUser(email)
userRepository.setUsername(userId, username)
userId // Return value from prepared block
}
}
}
// Manual lifecycle management (less common)
fun manualUsernameChange(usernameKey: UserUsernamePrepareKey, newUsername: String) {
val preparedValue = usernameKey.prepare(newUsername)
try {
// Perform operations with prepared value
usernameKey.commit(preparedValue)
} catch (e: Exception) {
usernameKey.rollback(preparedValue)
throw e
}
}