Class AdminUserPersistenceHandler
- All Implemented Interfaces:
com.broadleafcommerce.common.messaging.PersistenceHandler
AdminUser
data to update User
.
This is designed to perform a replacement of existing data within this service from the admin
user service.- Author:
- Samarth Dhruva (samarthd)
-
Constructor Summary
ConstructorDescriptionAdminUserPersistenceHandler
(UserService<User> userService, AuthorizedClientService<AuthorizedClient> clientService, com.fasterxml.jackson.databind.ObjectMapper mapper, com.broadleafcommerce.common.extension.TypeFactory typeFactory, UserLockoutService userLockoutService) -
Method Summary
Modifier and TypeMethodDescriptionprotected boolean
arePermissionsEqual
(Set<UserPermissionRef> newPermissions, Set<UserPermissionRef> existingPermissions) protected boolean
areRolesEqual
(Set<UserRoleRef> newRoles, Set<UserRoleRef> existingRoles) protected void
attemptCreateOrThrow
(@NonNull User newUser) For creation, we need a guarantee that only one attempt will succeed even in the event of concurrent duplicate messages or out-of-order messages.protected void
attemptReplaceOrThrow
(@NonNull String id, @NonNull User replacement, @NonNull Instant changeTimestamp) We cannot perform a normal "create or update" save operation here due to concurrency concerns.protected User
buildUserForCreate
(AdminUser request, Instant lastUpdated) protected AdminUser
deserialize
(com.fasterxml.jackson.databind.JsonNode jsonNode) findExistingAdminUser
(String serviceId) protected String
getAuthorizationServerId
(AdminUser request) protected AuthorizedClientService<AuthorizedClient>
String[]
protected com.broadleafcommerce.common.extension.TypeFactory
protected UserLockoutService
protected UserService<User>
void
protected void
logReceiptOfPersistenceMessage
(@NonNull com.broadleafcommerce.data.tracking.core.type.OperationType operationType, @NonNull Instant changeTimestamp, @NonNull String entityId) protected boolean
mapUpdatesFromRequest
(AdminUser request, User target) Perform any necessary updates of the admin user.protected void
modifyForArchival
(User target) Mimic whatUserService.archive(String)
would do to mark this record as archived.protected void
performArchivalReplacementIfEligible
(@NonNull User existing, @NonNull Instant changeTimestamp) protected void
performReplacementIfEligible
(@NonNull User existing, @NonNull AdminUser request, @NonNull Instant changeTimestamp) protected void
processCreateOperation
(@NonNull String entityId, @NonNull Instant changeTimestamp, @NonNull com.fasterxml.jackson.databind.JsonNode entityJson) Invoked if the persistence message had anOperationType
ofOperationType.CREATE
.protected void
processDeleteOperation
(@NonNull String entityId, @NonNull Instant changeTimestamp, @NonNull com.fasterxml.jackson.databind.JsonNode entityJson) Archives the given entity.protected void
processUpdateOperation
(@NonNull String entityId, @NonNull Instant changeTimestamp, @NonNull com.fasterxml.jackson.databind.JsonNode entityJson) Invoked if the persistence message had anOperationType
ofOperationType.UPDATE
.protected UserPermissionRef
toAuthPermissionRef
(AdminPermissionRef adminPermissionRef) Deprecated.Since 1.7.0.protected UserPermissionRef
protected RestrictedPermission
toAuthRestrictedPermission
(AdminRestrictedPermission adminRestrictedPermission) protected RestrictedRole
toAuthRestrictedRole
(AdminRestrictedRole adminRestrictedRole) protected Restriction
toAuthRestriction
(AdminRestriction adminRestriction) protected Restriction
toAuthRestriction
(String restrictionType, Set<String> restrictionTargets) protected UserRoleRef
toAuthRoleRef
(AdminRoleRef adminRoleRef) Deprecated.Since 1.7.0.protected UserRoleRef
toAuthRoleRef
(String id) protected boolean
updatePermissions
(AdminUser request, User user) We will not validate these references by querying for them, as the associated permissions may not yet be synchronized to the authentication service.protected boolean
updateUserInfo
(AdminUser request, User user) protected boolean
updateUserRestrictedPermissions
(AdminUser request, User user) protected boolean
updateUserRestrictedRoles
(AdminUser request, User user) protected boolean
updateUserRestrictions
(AdminUser request, User user) protected boolean
updateUserRoles
(AdminUser request, User user) We will not validate these references by querying for them, as the associated roles may not yet be synchronized to the authentication service.protected boolean
updateUserStatus
(AdminUser request, User user) protected boolean
updateUserTenantRestrictions
(AdminUser request, User user) Methods inherited from class com.broadleafcommerce.auth.user.listener.OperationAwarePersistenceHandler
getChangeTimestamp, getEntityIdOrThrow, getNonNullField, getValidOperationTypeOrThrow, processStateChange, processStateChange
Methods inherited from class com.broadleafcommerce.auth.user.listener.AuthDataUpdatePersistenceHandler
getObjectMapper, handle, isNodeNull, isValidType
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
Methods inherited from interface com.broadleafcommerce.common.messaging.PersistenceHandler
validate
-
Constructor Details
-
AdminUserPersistenceHandler
public AdminUserPersistenceHandler(UserService<User> userService, AuthorizedClientService<AuthorizedClient> clientService, com.fasterxml.jackson.databind.ObjectMapper mapper, com.broadleafcommerce.common.extension.TypeFactory typeFactory, UserLockoutService userLockoutService)
-
-
Method Details
-
hook
-
processCreateOperation
protected void processCreateOperation(@NonNull @NonNull String entityId, @NonNull @NonNull Instant changeTimestamp, @NonNull @NonNull com.fasterxml.jackson.databind.JsonNode entityJson) throws IOException Description copied from class:OperationAwarePersistenceHandler
Invoked if the persistence message had anOperationType
ofOperationType.CREATE
.- Specified by:
processCreateOperation
in classOperationAwarePersistenceHandler
- Parameters:
entityId
- the ID found on the persistence message. Guaranteed non-empty.changeTimestamp
- the timestamp found on the persistence message. Guaranteed non-null.entityJson
- the persistence message json itself. Guaranteed non-null.- Throws:
IOException
-
findExistingAdminUser
-
buildUserForCreate
-
mapUpdatesFromRequest
Perform any necessary updates of the admin user. If no update is necessary, this will return false.- Parameters:
request
- The updated admin usertarget
- The user to apply changes to- Returns:
- true if the user should be updated, else false
-
deserialize
protected AdminUser deserialize(com.fasterxml.jackson.databind.JsonNode jsonNode) throws IOException - Throws:
IOException
-
attemptCreateOrThrow
For creation, we need a guarantee that only one attempt will succeed even in the event of concurrent duplicate messages or out-of-order messages.Thus, we need to use a method here that will create a record with the given non-null
User.serviceId
andUser.type
with the minimum guarantee that only one record with the given values will ever be created (even if the requests are highly concurrent).This means that create can fail for two main reasons, either another operation beat us to it or one of the entity's references (ex:
User.getRoles()
) is not present. In either case, the exception thrown by this method should be bubbled up to trigger a retry. If it was due to another operation concurrently creating the record, the retry will resolve quietly after the eager fetch (inprocessCreateOperation(String, Instant, JsonNode)
,processUpdateOperation(String, Instant, JsonNode)
, orprocessDeleteOperation(String, Instant, JsonNode)
) finds the now-existing record and compares against its lastUpdated. If the error was due to missing references, the retry will keep trying until the referenced records have been created.TODO https://github.com/BroadleafCommerce/AuthenticationServices/issues/182
- Parameters:
newUser
- the entity to create. Must have a non-nullUser.serviceId
,User.type
, andUser.lastUpdated
.- Throws:
RuntimeException
- if the create failed due to a concurrent create happening, or if one of the entity's references was not found
-
logReceiptOfPersistenceMessage
-
processUpdateOperation
protected void processUpdateOperation(@NonNull @NonNull String entityId, @NonNull @NonNull Instant changeTimestamp, @NonNull @NonNull com.fasterxml.jackson.databind.JsonNode entityJson) throws IOException Description copied from class:OperationAwarePersistenceHandler
Invoked if the persistence message had anOperationType
ofOperationType.UPDATE
.- Specified by:
processUpdateOperation
in classOperationAwarePersistenceHandler
- Parameters:
entityId
- the entity ID found on the persistence message. Guaranteed non-empty.changeTimestamp
- the timestamp found on the persistence message. Guaranteed non-null.entityJson
- the persistence message json itself. Guaranteed non-null.- Throws:
IOException
-
performReplacementIfEligible
-
attemptReplaceOrThrow
protected void attemptReplaceOrThrow(@NonNull @NonNull String id, @NonNull @NonNull User replacement, @NonNull @NonNull Instant changeTimestamp) We cannot perform a normal "create or update" save operation here due to concurrency concerns. We need a guarantee that only one attempt will succeed even in the event of duplicate messages or out-of-order messages. Furthermore, the end result must be atomically updating an existing record only if its lastUpdated is before the current change.Thus, we invoke a special method that will directly attempt an update that the data store will reject if the entity is not found or has a lastUpdated ahead of the current change.
This means that replace can fail for two main reasons, either the user wasn't found with a valid lastUpdated or one of the entity's references (ex:
User.getRoles()
) is not present. In either case, the exception thrown by this method should be bubbled up to trigger a retry. If it was due to another operation concurrently modifying the record (which would change its lastUpdated), the retry will resolve quietly after the eager fetch (inprocessCreateOperation(String, Instant, JsonNode)
,processUpdateOperation(String, Instant, JsonNode)
, orprocessDeleteOperation(String, Instant, JsonNode)
) finds the updated record and compares against its lastUpdated. If the error was due to missing references, the retry will keep trying until the referenced record has been created.TODO https://github.com/BroadleafCommerce/AuthenticationServices/issues/182
- Parameters:
id
- theUser.getId()
of the entity to replacereplacement
- the replacement entitychangeTimestamp
- the lastUpdated of the current change- Throws:
RuntimeException
- if the replacement failed due to the entity not existing or having an invalid lastUpdated, or if one of the entity's references was not found
-
processDeleteOperation
protected void processDeleteOperation(@NonNull @NonNull String entityId, @NonNull @NonNull Instant changeTimestamp, @NonNull @NonNull com.fasterxml.jackson.databind.JsonNode entityJson) throws IOException Archives the given entity.Note that if an existing record is not found, one will be created in an archived state. The motivation for this is to protect against out-of-order messages (ex: "Delete" message on an entity arrives before the "Create"). By establishing a pre-existing record in an archived state with a timestamp, any subsequent persistence message received can be compared against this record's timestamp and appropriately discarded as outdated rather than triggering creation of a new record.
- Specified by:
processDeleteOperation
in classOperationAwarePersistenceHandler
- Parameters:
entityId
- the entity ID found on the persistence message. Guaranteed non-empty.changeTimestamp
- the timestamp found on the persistence message. Guaranteed non-null.entityJson
- the persistence message json itself. Guaranteed non-null.- Throws:
IOException
-
performArchivalReplacementIfEligible
-
modifyForArchival
Mimic whatUserService.archive(String)
would do to mark this record as archived.- Parameters:
target
- the instance to modify
-
updatePermissions
We will not validate these references by querying for them, as the associated permissions may not yet be synchronized to the authentication service. We trust the admin user service to have pre-validated these associations, and thus eventually no references will be broken.TODO https://github.com/BroadleafCommerce/AuthenticationServices/issues/182
- Parameters:
request
- the request whose permissions should be used to replace the existing datauser
- the target on which the permissions will be replaced
-
arePermissionsEqual
protected boolean arePermissionsEqual(Set<UserPermissionRef> newPermissions, Set<UserPermissionRef> existingPermissions) -
toAuthPermissionRef
Deprecated.Since 1.7.0. UsetoAuthPermissionRef(String)
-
toAuthPermissionRef
-
updateUserRoles
We will not validate these references by querying for them, as the associated roles may not yet be synchronized to the authentication service. We trust the admin user service to have pre-validated these associations, and thus eventually no references will be broken.TODO https://github.com/BroadleafCommerce/AuthenticationServices/issues/182
- Parameters:
request
- the request whose roles should be used to replace the existing datauser
- the target on which the roles will be replaced
-
areRolesEqual
-
toAuthRoleRef
Deprecated.Since 1.7.0. UsetoAuthRoleRef(String)
-
toAuthRoleRef
-
updateUserInfo
-
updateUserStatus
-
updateUserTenantRestrictions
-
updateUserRestrictions
-
toAuthRestriction
-
updateUserRestrictedRoles
-
toAuthRestrictedRole
-
updateUserRestrictedPermissions
-
toAuthRestrictedPermission
protected RestrictedPermission toAuthRestrictedPermission(AdminRestrictedPermission adminRestrictedPermission) -
toAuthRestriction
-
getAuthorizationServerId
-
getSupportedSimpleTypeNames
-
getUserService
-
getClientService
-
getTypeFactory
protected com.broadleafcommerce.common.extension.TypeFactory getTypeFactory() -
getUserLockoutService
-