class DBService implements RolesProvider {

    void executePutRoleReview(ResourceContext ctx, String domainName, String roleName, Role role,
                              String auditRef, String caller) {

        // our exception handling code does the check for retry count
        // and throws the exception it had received when the retry
        // count reaches 0

        for (int retryCount = defaultRetryCount; ; retryCount--) {

            try (ObjectStoreConnection con = store.getConnection(false, true)) {

                final String principal = getPrincipalName(ctx);

                // first verify that auditing requirements are met

                checkDomainAuditEnabled(con, domainName, auditRef, caller, principal, AUDIT_TYPE_ROLE);

                // retrieve our original role

                Role originalRole = getRole(con, domainName, roleName, false, false, false);

                if (originalRole.getTrust() != null && !originalRole.getTrust().isEmpty()) {
                    throw ZMSUtils.requestError(caller + ": role " + roleName + " is delegated. Review should happen on the trusted role. ", caller);
                }

                // now process the request. first we're going to make a copy of our role

                Role updatedRole = new Role()
                        .setName(originalRole.getName());

                // then we're going to apply the updated expiry and/or active status from the incoming role

                List<RoleMember> noactionMembers = applyMembershipChanges(updatedRole, originalRole, role, auditRef);

                StringBuilder auditDetails = new StringBuilder(ZMSConsts.STRING_BLDR_SIZE_DEFAULT);

                List<RoleMember> deletedMembers = new ArrayList<>();
                List<RoleMember> extendedMembers = new ArrayList<>();

                auditDetails.append("{\"name\": \"").append(roleName).append('\"')
                        .append(", \"selfServe\": ").append(auditLogBooleanDefault(originalRole.getSelfServe(), Boolean.TRUE))
                        .append(", \"auditEnabled\": ").append(auditLogBooleanDefault(originalRole.getAuditEnabled(), Boolean.TRUE));

                for (RoleMember member : updatedRole.getRoleMembers()) {

                    // if active flag is coming as false for the member, that means it's flagged for deletion

                    if (member.getActive() == Boolean.FALSE) {
                        if (!con.deleteRoleMember(domainName, roleName, member.getMemberName(), principal, auditRef)) {
                            con.rollbackChanges();
                            throw ZMSUtils.notFoundError(caller + ": unable to delete role member: " +
                                    member.getMemberName() + " from role: " + roleName, caller);
                        }
                        deletedMembers.add(member);

                    } else {
                        // if not marked for deletion, then we are going to extend the member

                        if (!con.insertRoleMember(domainName, roleName, member, principal, auditRef)) {
                            con.rollbackChanges();
                            throw ZMSUtils.notFoundError(caller + ": unable to extend role member: " +
                                    member.getMemberName() + " for the role: " + roleName, caller);
                        }
                        extendedMembers.add(member);
                    }
                }

                // construct audit log details

                auditLogRoleMembers(auditDetails, "deleted-members", deletedMembers);
                auditLogRoleMembers(auditDetails, "extended-members", extendedMembers);
                auditLogRoleMembers(auditDetails, "no-action-members", noactionMembers);

                auditDetails.append("}");

                if (!deletedMembers.isEmpty() || !extendedMembers.isEmpty()) {
                    // we have one or more changes to the role. We should update
                    // both lastReviewed as well as modified timestamps
                    con.updateRoleModTimestamp(domainName, roleName);
                }

                con.updateRoleReviewTimestamp(domainName, roleName);
                saveChanges(con, domainName);

                // audit log the request

                auditLogRequest(ctx, domainName, auditRef, caller, "REVIEW", roleName, auditDetails.toString());

                return;

            } catch (ResourceException ex) {
                if (!shouldRetryOperation(ex, retryCount)) {
                    throw ex;
                }
            }
        }
    }

    public  DBService(ObjectStore store, AuditLogger auditLogger, ZMSConfig zmsConfig, AuditReferenceValidator auditReferenceValidator);

}