@Override
  public List<RoleMember> getPrimaryRoleMembersInWorkArea(
      String namespaceCode,
      String roleName,
      Long workArea,
      DateTime asOfDate,
      boolean isActiveOnly) {
    // the return value
    List<RoleMember> primaryRoleMembers = new ArrayList<RoleMember>();

    Role role = getRoleService().getRoleByNamespaceCodeAndName(namespaceCode, roleName);
    if (role != null) {
      Map<String, String> qualification = new HashMap<String, String>();
      qualification.put(
          KPMERoleMemberAttribute.WORK_AREA.getRoleMemberAttributeName(), String.valueOf(workArea));
      primaryRoleMembers =
          getRoleServiceHelper().getPrimaryRoleMembers(role, qualification, asOfDate, isActiveOnly);
    } else {
      LOG.error(
          "Role instance for role with name "
              + roleName
              + " namespace "
              + namespaceCode
              + " was null");
    }

    return primaryRoleMembers;
  }
  public List<String> getDepartmentsForPrincipalInRoles(
      String principalId, List<String> roleIds, DateTime asOfDate, boolean isActiveOnly) {
    Set<String> departments = new HashSet<String>();

    Map<String, String> qualifiers = new HashMap<String, String>();
    qualifiers.put(KPMERoleMemberAttribute.WORK_AREA.getRoleMemberAttributeName(), "%");
    qualifiers.put(KPMERoleMemberAttribute.LOCATION.getRoleMemberAttributeName(), "%");
    qualifiers.put(KPMERoleMemberAttribute.DEPARTMENT.getRoleMemberAttributeName(), "%");
    qualifiers.put(KPMERoleMemberAttribute.GROUP_KEY_CODE.getRoleMemberAttributeName(), "%");
    List<Map<String, String>> roleQualifiers =
        getRoleQualifiers(principalId, roleIds, qualifiers, asOfDate, isActiveOnly);

    for (Map<String, String> roleQualifier : roleQualifiers) {
      String department =
          MapUtils.getString(
              roleQualifier, KPMERoleMemberAttribute.DEPARTMENT.getRoleMemberAttributeName());
      String groupKeyCode =
          MapUtils.getString(
              roleQualifier, KPMERoleMemberAttribute.GROUP_KEY_CODE.getRoleMemberAttributeName());
      if (department != null && groupKeyCode != null) {
        departments.add(groupKeyCode + "|" + department);
      }
    }

    List<String> locations =
        getLocationsForPrincipalInRoles(principalId, roleIds, asOfDate, isActiveOnly);
    departments.addAll(
        getDepartmentService().getDepartmentValuesWithLocations(locations, asOfDate.toLocalDate()));

    return new ArrayList<String>(departments);
  }
  public boolean principalHasRoleInWorkArea(
      String principalId, String namespaceCode, String roleName, Long workArea, DateTime asOfDate) {
    Map<String, String> qualification = new HashMap<String, String>();
    qualification.put(
        KPMERoleMemberAttribute.WORK_AREA.getRoleMemberAttributeName(), String.valueOf(workArea));

    return principalHasRole(principalId, namespaceCode, roleName, qualification, asOfDate);
  }
  protected Map<String, String> addCustomDerivedQualifications(
      Map<String, String> qualificiation, DateTime asOfDate, boolean activeOnly) {
    Map<String, String> qual = new HashMap<String, String>();
    qual.putAll(qualificiation);
    qual.put("asOfDate", asOfDate.toString());
    qual.put("activeOnly", Boolean.toString(activeOnly));

    return qual;
  }
  public List<RoleMember> getRoleMembersInLocation(
      String namespaceCode,
      String roleName,
      String location,
      DateTime asOfDate,
      boolean isActiveOnly) {
    Map<String, String> qualification = new HashMap<String, String>();
    qualification.put(KPMERoleMemberAttribute.LOCATION.getRoleMemberAttributeName(), location);

    return getRoleMembers(namespaceCode, roleName, qualification, asOfDate, isActiveOnly);
  }
  public boolean principalHasRoleInLocation(
      String principalId,
      String namespaceCode,
      String roleName,
      String location,
      DateTime asOfDate) {
    Map<String, String> qualification = new HashMap<String, String>();
    qualification.put(KPMERoleMemberAttribute.LOCATION.getRoleMemberAttributeName(), location);

    return principalHasRole(principalId, namespaceCode, roleName, qualification, asOfDate);
  }
  public List<RoleMember> getRoleMembersInWorkArea(
      String namespaceCode,
      String roleName,
      Long workArea,
      DateTime asOfDate,
      boolean isActiveOnly) {
    Map<String, String> qualification = new HashMap<String, String>();
    qualification.put(
        KPMERoleMemberAttribute.WORK_AREA.getRoleMemberAttributeName(), String.valueOf(workArea));

    return getRoleMembers(namespaceCode, roleName, qualification, asOfDate, isActiveOnly);
  }
 public List<RoleMember> getRoleMembersInDepartment(
     String namespaceCode,
     String roleName,
     String department,
     String groupKeyCode,
     DateTime asOfDate,
     boolean isActiveOnly) {
   Map<String, String> qualification = new HashMap<String, String>();
   qualification.put(KPMERoleMemberAttribute.DEPARTMENT.getRoleMemberAttributeName(), department);
   qualification.put(
       KPMERoleMemberAttribute.GROUP_KEY_CODE.getRoleMemberAttributeName(), groupKeyCode);
   return getRoleMembers(namespaceCode, roleName, qualification, asOfDate, isActiveOnly);
 }
 public boolean principalHasRoleInDepartment(
     String principalId,
     String namespaceCode,
     String roleName,
     String department,
     String groupKeyCode,
     DateTime asOfDate) {
   Map<String, String> qualification = new HashMap<String, String>();
   qualification.put(KPMERoleMemberAttribute.DEPARTMENT.getRoleMemberAttributeName(), department);
   qualification.put(
       KPMERoleMemberAttribute.GROUP_KEY_CODE.getRoleMemberAttributeName(), groupKeyCode);
   return principalHasRole(principalId, namespaceCode, roleName, qualification, asOfDate);
 }
  public List<String> getLocationsForPrincipalInRoles(
      String principalId, List<String> roleIds, DateTime asOfDate, boolean isActiveOnly) {
    Set<String> locations = new HashSet<String>();

    Map<String, String> qualifiers = new HashMap<String, String>();
    qualifiers.put(KPMERoleMemberAttribute.WORK_AREA.getRoleMemberAttributeName(), "%");
    qualifiers.put(KPMERoleMemberAttribute.LOCATION.getRoleMemberAttributeName(), "%");
    qualifiers.put(KPMERoleMemberAttribute.DEPARTMENT.getRoleMemberAttributeName(), "%");
    qualifiers.put(KPMERoleMemberAttribute.GROUP_KEY_CODE.getRoleMemberAttributeName(), "%");
    List<Map<String, String>> roleQualifiers =
        getRoleQualifiers(principalId, roleIds, qualifiers, asOfDate, isActiveOnly);

    for (Map<String, String> roleQualifier : roleQualifiers) {
      String location =
          MapUtils.getString(
              roleQualifier, KPMERoleMemberAttribute.LOCATION.getRoleMemberAttributeName());

      if (location != null) {
        locations.add(location);
      }
    }

    return new ArrayList<String>(locations);
  }
  public boolean principalHasRole(
      String principalId,
      String namespaceCode,
      String roleName,
      Map<String, String> qualification,
      DateTime asOfDate) {
    boolean principalHasRole = false;

    String roleId = getRoleService().getRoleIdByNamespaceCodeAndName(namespaceCode, roleName);

    if (roleId == null) {
      return false;
    }
    if (asOfDate.compareTo(LocalDate.now().toDateTimeAtStartOfDay()) == 0) {
      principalHasRole =
          getRoleService()
              .principalHasRole(principalId, Collections.singletonList(roleId), qualification);
    } else {
      List<RoleMember> roleMembers =
          getRoleMembers(namespaceCode, roleName, qualification, asOfDate, true);

      for (RoleMember roleMember : roleMembers) {
        if (MemberType.PRINCIPAL.equals(roleMember.getType())) {
          if (StringUtils.equals(roleMember.getMemberId(), principalId)) {
            principalHasRole = true;
            break;
          }
        } else if (MemberType.GROUP.equals(roleMember.getType())) {
          if (HrServiceLocator.getKPMEGroupService()
              .isMemberOfGroupWithId(principalId, roleMember.getMemberId(), asOfDate)) {
            // if (getGroupService().isMemberOfGroup(principalId, roleMember.getMemberId())) {
            principalHasRole = true;
            break;
          }
        } else if (MemberType.ROLE.equals(roleMember.getType())) {
          Role derivedRole =
              getRoleService()
                  .getRoleByNamespaceCodeAndName(
                      KPMENamespace.KPME_HR.getNamespaceCode(),
                      KPMERole.DERIVED_ROLE_POSITION.getRoleName());
          // check if the member represents the (nested) derived role 'position'
          if (derivedRole != null && roleMember.getMemberId().equals(derivedRole.getId())) {
            // add custom attributes
            Map<String, String> qual = new HashMap<String, String>();
            qual.putAll(roleMember.getAttributes());
            qual.put("asOfDate", asOfDate.toString());
            // return true if the principal id is a member of the (nested) derived role 'position'
            RoleTypeService roleTypeService = getRoleTypeService(derivedRole);
            if (roleTypeService.hasDerivedRole(
                principalId,
                new ArrayList<String>(),
                derivedRole.getNamespaceCode(),
                derivedRole.getName(),
                qual)) {
              principalHasRole = true;
              break;
            }
          }
        }
      }
    }

    return principalHasRole;
  }
  protected List<RoleMember> getPrimaryRoleMembers(
      Role role, Map<String, String> qualification, DateTime asOfDate, boolean isActiveOnly) {
    // define the return value
    List<RoleMember> primaryRoleMembers = new ArrayList<RoleMember>();

    if (role != null) {
      RoleTypeService roleTypeService = getRoleTypeService(role);
      // use predicate based filtering only on non-derived role.
      if (roleTypeService == null || !roleTypeService.isDerivedRoleType()) {
        List<Predicate> predicates = new ArrayList<Predicate>();
        predicates.add(equal(KimConstants.PrimaryKeyConstants.SUB_ROLE_ID, role.getId()));
        if (isActiveOnly) {
          predicates.add(
              or(isNull("activeFromDateValue"), lessThanOrEqual("activeFromDateValue", asOfDate)));
          predicates.add(
              or(isNull("activeToDateValue"), greaterThan("activeToDateValue", asOfDate)));
        }

        // LookupCustomizer<RoleMemberBo> lookupCustomizer = builder.build();
        // guard for default type roles
        if (roleTypeService != null) {
          if (MapUtils.isEmpty(qualification)) {
            primaryRoleMembers =
                getRoleService()
                    .findRoleMembers(
                        QueryByCriteria.Builder.fromPredicates(
                            predicates.toArray(new Predicate[predicates.size()])))
                    .getResults();
          } else {
            // get the keys (name) of the qualifiers needed for membership in this role
            List<String> attributesForExactMatch = roleTypeService.getQualifiersForExactMatch();
            if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
              if (attributesForExactMatch.size() <= 1) {
                for (Map.Entry<String, String> qualificationEntry : qualification.entrySet()) {
                  // do not add a qualification predicate for an attribute unless it is required for
                  // matching

                  if (attributesForExactMatch.contains(qualificationEntry.getKey())) {
                    predicates.add(
                        equal(
                            "attributes[" + qualificationEntry.getKey() + "]",
                            qualificationEntry.getValue()));
                  }
                }
                primaryRoleMembers =
                    getRoleService()
                        .findRoleMembers(
                            QueryByCriteria.Builder.fromPredicates(
                                predicates.toArray(new Predicate[predicates.size()])))
                        .getResults();

              } else {
                // rice's transformation doesn't work with more than one attribute.
                // here is a terrible hack
                List<RoleMember> intersectedMembers = null;
                for (Map.Entry<String, String> qualificationEntry : qualification.entrySet()) {
                  // do not add a qualification predicate for an attribute unless it is required for
                  // matching

                  if (attributesForExactMatch.contains(qualificationEntry.getKey())) {
                    Predicate attrPredicates =
                        equal(
                            "attributes[" + qualificationEntry.getKey() + "]",
                            qualificationEntry.getValue());
                    Predicate[] tempPredicates =
                        predicates.toArray(new Predicate[predicates.size() + 1]);
                    tempPredicates[predicates.size()] = attrPredicates;
                    List<RoleMember> tempMembers =
                        new ArrayList<RoleMember>(
                            getRoleService()
                                .findRoleMembers(
                                    QueryByCriteria.Builder.fromPredicates(tempPredicates))
                                .getResults());
                    if (intersectedMembers == null) {
                      intersectedMembers = new ArrayList<>();
                      intersectedMembers.addAll(tempMembers);
                    } else {
                      intersectedMembers = intersect(intersectedMembers, tempMembers);
                    }
                  }
                }
                primaryRoleMembers = intersectedMembers;
              }
            }
          }
        }
      } else {
        // for derived roles just add the as-of date and active only flag to a copy of the
        // qualification
        Map<String, String> derivedRoleQualification = new HashMap<String, String>(qualification);
        derivedRoleQualification.put("asOfDate", asOfDate.toString());
        derivedRoleQualification.put("activeOnly", String.valueOf(isActiveOnly));
        List<RoleMembership> derivedRoleMembers =
            roleTypeService.getRoleMembersFromDerivedRole(
                role.getNamespaceCode(), role.getName(), derivedRoleQualification);
        // convert the role memberships into role members
        for (RoleMembership derivedRoleMember : derivedRoleMembers) {
          RoleMember roleMember =
              RoleMember.Builder.create(
                      derivedRoleMember.getRoleId(),
                      derivedRoleMember.getId(),
                      derivedRoleMember.getMemberId(),
                      derivedRoleMember.getType(),
                      null,
                      null,
                      derivedRoleMember.getQualifier(),
                      role.getName(),
                      role.getNamespaceCode())
                  .build();

          primaryRoleMembers.add(roleMember);
        }
      }
    }

    return primaryRoleMembers;
  }