/**
   * @param entity
   * @param userDn
   * @return
   * @throws org.apache.directory.fortress.core.UpdateException
   */
  Group deassign(Group entity, String userDn) throws FinderException, UpdateException {
    LdapConnection ld = null;
    String dn = getDn(entity.getName(), entity.getContextId());
    LOG.debug("deassign group property dn [{}], member dn [{}]", dn, userDn);

    try {
      List<Modification> mods = new ArrayList<Modification>();
      mods.add(
          new DefaultModification(
              ModificationOperation.REMOVE_ATTRIBUTE, SchemaConstants.MEMBER_AT, userDn));

      ld = getAdminConnection();
      modify(ld, dn, mods, entity);
    } catch (LdapException e) {
      String error =
          "deassign group name ["
              + entity.getName()
              + "] user dn ["
              + userDn
              + "] caught "
              + "LDAPException="
              + e.getMessage();
      throw new UpdateException(GlobalErrIds.GROUP_USER_DEASSIGN_FAILED, error, e);
    } finally {
      closeAdminConnection(ld);
    }

    return get(entity);
  }
  /**
   * @param group
   * @throws org.apache.directory.fortress.core.CreateException
   */
  Group create(Group group) throws CreateException {
    LdapConnection ld = null;
    String nodeDn = getDn(group.getName(), group.getContextId());

    try {
      LOG.debug("create group dn [{}]", nodeDn);
      Entry myEntry = new DefaultEntry(nodeDn);
      myEntry.add(SchemaConstants.OBJECT_CLASS_AT, GROUP_OBJ_CLASS);
      myEntry.add(SchemaConstants.CN_AT, group.getName());
      // protocol is required:
      myEntry.add(GROUP_PROTOCOL_ATTR_IMPL, group.getProtocol());
      // type is required:
      myEntry.add(GlobalIds.TYPE, group.getType().toString());

      loadAttrs(group.getMembers(), myEntry, SchemaConstants.MEMBER_AT);
      loadProperties(group.getProperties(), myEntry, GROUP_PROPERTY_ATTR_IMPL, '=');

      if (StringUtils.isNotEmpty(group.getDescription())) {
        myEntry.add(SchemaConstants.DESCRIPTION_AT, group.getDescription());
      }

      ld = getAdminConnection();
      add(ld, myEntry);
    } catch (LdapException e) {
      String error = "create group node dn [" + nodeDn + "] caught LDAPException=" + e.getMessage();
      throw new CreateException(GlobalErrIds.GROUP_ADD_FAILED, error, e);
    } finally {
      closeAdminConnection(ld);
    }

    return group;
  }
  private void loadUserDns(Group group) throws SecurityException {
    if (CollectionUtils.isNotEmpty(group.getMembers())) {
      ReviewMgr reviewMgr = ReviewMgrFactory.createInstance();
      List<String> userDns = new ArrayList<String>();

      for (String member : group.getMembers()) {
        User user = reviewMgr.readUser(new User(member));
        userDns.add(user.getDn());
      }

      group.setMembers(userDns);
    }
  }
  private void loadRoleDns(Group group) throws SecurityException {
    if (CollectionUtils.isNotEmpty(group.getMembers())) {
      ReviewMgr reviewMgr = ReviewMgrFactory.createInstance(this.contextId);
      List<String> roleDns = new ArrayList<String>();

      for (String member : group.getMembers()) {
        Role role = reviewMgr.readRole(new Role(member));
        roleDns.add(role.getDn());
      }

      group.setMembers(roleDns);
    }
  }
 /**
  * This method will remove group node from diretory.
  *
  * @param group
  * @throws org.apache.directory.fortress.core.RemoveException
  */
 Group remove(Group group) throws RemoveException {
   LdapConnection ld = null;
   String nodeDn = getDn(group.getName(), group.getContextId());
   LOG.debug("remove group dn [{}]", nodeDn);
   try {
     ld = getAdminConnection();
     delete(ld, nodeDn, group);
   } catch (LdapException e) {
     String error = "remove group node dn [" + nodeDn + "] caught LDAPException=" + e.getMessage();
     throw new RemoveException(GlobalErrIds.GROUP_DELETE_FAILED, error, e);
   } finally {
     closeAdminConnection(ld);
   }
   return group;
 }
  /** {@inheritDoc} */
  @Override
  public Group add(Group group) throws org.apache.directory.fortress.core.SecurityException {
    String methodName = "add";
    assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
    checkAccess(CLS_NM, methodName);

    if (!group.isMemberDn()) {
      if (group.getType() == Group.Type.ROLE) {
        loadRoleDns(group);
      } else {
        loadUserDns(group);
      }
      group.setMemberDn(true);
    }

    return GROUP_P.add(group);
  }
  /**
   * @param le
   * @param sequence
   * @return
   * @throws LdapException
   */
  private Group unloadLdapEntry(Entry le, long sequence) throws LdapInvalidAttributeValueException {
    Group entity = new ObjectFactory().createGroup();
    entity.setName(getAttribute(le, SchemaConstants.CN_AT));
    entity.setDescription(getAttribute(le, SchemaConstants.DESCRIPTION_AT));
    String typeAsString = getAttribute(le, GlobalIds.TYPE);
    if (StringUtils.isNotEmpty(typeAsString)) {
      entity.setType(Group.Type.valueOf(typeAsString.toUpperCase()));
    }
    entity.setProtocol(getAttribute(le, GROUP_PROTOCOL_ATTR_IMPL));
    entity.setMembers(getAttributes(le, SchemaConstants.MEMBER_AT));
    entity.setMemberDn(true);
    entity.setProperties(PropUtil.getProperties(getAttributes(le, GROUP_PROPERTY_ATTR_IMPL), '='));
    entity.setSequenceId(sequence);

    return entity;
  }
  Group delete(Group group, String key, String value) throws FinderException, RemoveException {
    LdapConnection ld = null;
    String nodeDn = getDn(group.getName(), group.getContextId());

    try {
      LOG.debug("delete group property dn [{}], key [{}], value [{}]", nodeDn, key, value);
      List<Modification> mods = new ArrayList<Modification>();
      mods.add(
          new DefaultModification(
              ModificationOperation.REMOVE_ATTRIBUTE, GROUP_PROPERTY_ATTR_IMPL, key + "=" + value));
      ld = getAdminConnection();
      modify(ld, nodeDn, mods, group);
    } catch (LdapException e) {
      String error =
          "delete group property node dn [" + nodeDn + "] caught LDAPException=" + e.getMessage();
      throw new RemoveException(GlobalErrIds.GROUP_DELETE_PROPERTY_FAILED, error, e);
    } finally {
      closeAdminConnection(ld);
    }
    return get(group);
  }
  /** {@inheritDoc} */
  @Override
  public Group assign(Group group, String member) throws SecurityException {
    String methodName = "assign";
    assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
    checkAccess(CLS_NM, methodName);
    ReviewMgr reviewMgr = ReviewMgrFactory.createInstance(this.contextId);
    String dn;
    if (group.getType() == Group.Type.ROLE) {
      Role inRole = new Role(member);
      inRole.setContextId(group.getContextId());
      Role role = reviewMgr.readRole(inRole);
      dn = role.getDn();
      // Validate SSD constraints
      SDUtil.getInstance().validateSSD(group, role);
    } else {
      User inUser = new User(member);
      inUser.setContextId(group.getContextId());
      User user = reviewMgr.readUser(inUser);
      dn = user.getDn();
    }

    return GROUP_P.assign(group, dn);
  }
  /**
   * @param group
   * @return
   * @throws org.apache.directory.fortress.core.FinderException
   */
  List<Group> find(Group group) throws FinderException {
    List<Group> groupList = new ArrayList<>();
    LdapConnection ld = null;
    SearchCursor searchResults;
    String groupRoot = getRootDn(group.getContextId(), GlobalIds.GROUP_ROOT);
    String filter = null;

    try {
      String searchVal = encodeSafeText(group.getName(), GlobalIds.ROLE_LEN);
      filter =
          GlobalIds.FILTER_PREFIX
              + GROUP_OBJECT_CLASS_IMPL
              + ")("
              + SchemaConstants.CN_AT
              + "="
              + searchVal
              + "*))";
      ld = getAdminConnection();
      searchResults =
          search(
              ld, groupRoot, SearchScope.ONELEVEL, filter, GROUP_ATRS, false, GlobalIds.BATCH_SIZE);
      long sequence = 0;
      while (searchResults.next()) {
        groupList.add(unloadLdapEntry(searchResults.getEntry(), sequence++));
      }
    } catch (CursorException e) {
      String error = "find filter [" + filter + "] caught CursorException=" + e.getMessage();
      throw new FinderException(GlobalErrIds.GROUP_SEARCH_FAILED, error, e);
    } catch (LdapException e) {
      String error = "find filter [" + filter + "] caught LDAPException=" + e.getMessage();
      throw new FinderException(GlobalErrIds.GROUP_SEARCH_FAILED, error, e);
    } finally {
      closeAdminConnection(ld);
    }

    return groupList;
  }
  /**
   * @param group
   * @return
   * @throws org.apache.directory.fortress.core.FinderException
   */
  Group get(Group group) throws FinderException {
    Group entity = null;
    LdapConnection ld = null;
    String dn = getDn(group.getName(), group.getContextId());

    try {
      ld = getAdminConnection();
      Entry findEntry = read(ld, dn, GROUP_ATRS);
      if (findEntry == null) {
        String warning = "No Group entry found dn [" + dn + "]";
        throw new FinderException(GlobalErrIds.GROUP_NOT_FOUND, warning);
      }
      entity = unloadLdapEntry(findEntry, 0);
    } catch (LdapNoSuchObjectException e) {
      String warning = "read Obj COULD NOT FIND ENTRY for dn [" + dn + "]";
      throw new FinderException(GlobalErrIds.GROUP_NOT_FOUND, warning, e);
    } catch (LdapException e) {
      String error = "read dn [" + dn + "] LdapException=" + e.getMessage();
      throw new FinderException(GlobalErrIds.GROUP_READ_FAILED, error, e);
    } finally {
      closeAdminConnection(ld);
    }
    return entity;
  }
  /** {@inheritDoc} */
  @Override
  public Group deassign(Group group, String member) throws SecurityException {
    String methodName = "deassign";
    assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
    checkAccess(CLS_NM, methodName);
    ReviewMgr reviewMgr = ReviewMgrFactory.createInstance(this.contextId);
    String dn;
    if (group.getType() == Group.Type.ROLE) {
      Role role = reviewMgr.readRole(new Role(member));
      dn = role.getDn();
    } else {
      User user = reviewMgr.readUser(new User(member));
      dn = user.getDn();
    }

    return GROUP_P.deassign(group, dn);
  }
  /**
   * @param group
   * @return
   * @throws org.apache.directory.fortress.core.CreateException
   */
  Group update(Group group) throws FinderException, UpdateException {
    LdapConnection ld = null;
    String nodeDn = getDn(group.getName(), group.getContextId());

    try {
      LOG.debug("update group dn [{}]", nodeDn);
      List<Modification> mods = new ArrayList<Modification>();

      if (StringUtils.isNotEmpty(group.getDescription())) {
        mods.add(
            new DefaultModification(
                ModificationOperation.REPLACE_ATTRIBUTE,
                SchemaConstants.DESCRIPTION_AT,
                group.getDescription()));
      }

      if (StringUtils.isNotEmpty(group.getProtocol())) {
        mods.add(
            new DefaultModification(
                ModificationOperation.REPLACE_ATTRIBUTE,
                GROUP_PROTOCOL_ATTR_IMPL,
                group.getProtocol()));
      }

      loadAttrs(group.getMembers(), mods, SchemaConstants.MEMBER_AT);
      loadProperties(group.getProperties(), mods, GROUP_PROPERTY_ATTR_IMPL, true, '=');

      if (mods.size() > 0) {
        ld = getAdminConnection();
        modify(ld, nodeDn, mods, group);
      }
    } catch (LdapException e) {
      String error = "update group node dn [" + nodeDn + "] caught LDAPException=" + e.getMessage();
      throw new UpdateException(GlobalErrIds.GROUP_UPDATE_FAILED, error, e);
    } finally {
      closeAdminConnection(ld);
    }
    return get(group);
  }