class DBService implements RolesProvider {

    void executePutMembership(ResourceContext ctx, String domainName, String roleName,
            RoleMember roleMember, 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(true, true)) {

                String principal = getPrincipalName(ctx);

                // first verify that auditing requirements are met

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

                // make sure the role auditing requirements are met

                Role originalRole = con.getRole(domainName, roleName);
                if (originalRole == null) {
                    con.rollbackChanges();
                    throw ZMSUtils.notFoundError(caller + ": Unknown role: " + roleName, caller);
                }

                checkObjectAuditEnabled(con, originalRole.getAuditEnabled(), originalRole.getName(),
                        auditRef, caller, principal);

                // before inserting a member we need to verify that
                // this is a group role and not a delegated one.

                if (isTrustRole(originalRole)) {
                    con.rollbackChanges();
                    throw ZMSUtils.requestError(caller + ": " + roleName +
                            "is a delegated role", caller);
                }

                // now we need verify our quota check

                quotaCheck.checkRoleMembershipQuota(con, domainName, roleName, caller);

                // process our insert role member support. since this is a "single"
                // operation, we are not using any transactions.

                if (!con.insertRoleMember(domainName, roleName, roleMember,
                        principal, auditRef)) {
                    con.rollbackChanges();
                    throw ZMSUtils.requestError(caller + ": unable to insert role member: " +
                            roleMember.getMemberName() + " to role: " + roleName, caller);
                }

                // update our role and domain time-stamps, and invalidate local cache entry

                con.updateRoleModTimestamp(domainName, roleName);
                con.updateDomainModTimestamp(domainName);
                cacheStore.invalidate(domainName);

                // audit log the request

                StringBuilder auditDetails = new StringBuilder(ZMSConsts.STRING_BLDR_SIZE_DEFAULT);
                auditLogRoleMember(auditDetails, roleMember, true);
                auditLogRequest(ctx, domainName, auditRef, caller, ZMSConsts.HTTP_PUT, roleName,
                        auditDetails.toString());

                return;

            } catch (ResourceException ex) {

                // otherwise check if we need to retry or return failure

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

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

}