private Group getGroupByDN(LdapName groupDN, Set<String> membersToIgnore) throws NamingException {
        LdapContext ctx = null;
        try {
            LdapName baseDN;
            Name relativeDN;
            if (manager.getAlternateBaseDN() != null
                && groupDN.startsWith(manager.getAlternateBaseDN())) {
                baseDN = manager.getAlternateBaseDN();
            } else if (groupDN.startsWith(manager.getBaseDN())) {
                baseDN = manager.getBaseDN();
            }
            else {
                throw new IllegalArgumentException("GroupDN does not match any baseDN");
            }
            relativeDN = groupDN.getSuffix(baseDN.size());
            membersToIgnore.add(groupDN.toString());
            // Load record.
            ctx = manager.getContext(baseDN);
            Attributes attrs = ctx.getAttributes(relativeDN, standardAttributes);

            if (!PROCESSBIGGROUPS.getValue())
            {
                return processGroup(ctx, attrs, membersToIgnore);
            }
            else
            {
                boolean paging = false;
    
                NamingEnumeration<? extends Attribute> i = attrs.getAll();
                int rangehigh=-1;
                int oldrangehigh=-1;
    
                while (i.hasMore())
                {
                    Attribute attribute = i.next();
                    String key = attribute.getID().toLowerCase();
                    if (key.startsWith(manager.getGroupMemberField())&&key.contains(";range="))
                    {
                        rangehigh = Integer.parseInt(key.substring(key.indexOf(";range=")+";range=".length()).split("\\-")[1]);
    
                        paging=true;
                        Log.debug("using range retrival for group: {}", relativeDN);
                        break;
                    }
                }
    
                if (!paging)
                {
                    return processGroup(ctx, attrs, membersToIgnore);
                }
                else
                {
                    //retrieve first part with attributes that came from AD
                    ArrayList<String> stdAttr= new ArrayList<>();
                    for (int n=0;n<standardAttributes.length;n++)
                    {
                        if (!standardAttributes[n].contains(manager.getGroupMemberField()))
                        {
                            stdAttr.add(standardAttributes[n]);
                        }
                    }
    
                    stdAttr.add(manager.getGroupMemberField()+";range=0-"+String.valueOf(rangehigh));
                    Log.debug("first range will be 0-{}",rangehigh);
    
                    //reload Attributes as said in MSDN will prepare range retrival
                    attrs = ctx.getAttributes(relativeDN, stdAttr.toArray(new String[stdAttr.size()]));
    
                    //get the first part of the group
                    Group tmpGroup = processGroup(ctx, attrs, membersToIgnore);
                    Collection<JID> admins = tmpGroup.getAdmins();
                    String description = tmpGroup.getDescription();
                    String name = tmpGroup.getName();
                    ArrayList<JID> members = new ArrayList<>();
                    members.addAll(tmpGroup.getMembers());
    
                    //now load the rest
                    do
                    {
                        try
                        {
                            stdAttr.clear();
                            for (int n=0;n<standardAttributes.length;n++)
                            {
                                if (!standardAttributes[n].contains(manager.getGroupMemberField()))
                                {
                                    stdAttr.add(standardAttributes[n]);
                                }
                            }
                            //Add the next range rangehigh+1 to rangehigh+1+ldap.pagedResultsSize
                            stdAttr.add(genNextRangePart(rangehigh));
    
                            attrs = ctx.getAttributes(relativeDN, stdAttr.toArray(new String[stdAttr.size()]));
                            NamingEnumeration<? extends Attribute> inext = attrs.getAll();
                            while (inext.hasMore())
                            {
                                Attribute attribute = inext.next();
                                String key = attribute.getID().toLowerCase();
                                if (key.startsWith(manager.getGroupMemberField())&&key.contains(";range="))
                                {
                                    //get next rangehigh
                                    oldrangehigh=rangehigh;
                                    if (key.substring(key.indexOf(";range=")+";range=".length()).split("\\-")[1].equals("*")==false)
                                    {
                                        //we will have a minimum of two more ranges
                                        rangehigh = Integer.parseInt(key.substring(key.indexOf(";range=")+";range=".length()).split("\\-")[1]);
                                    }
                                    else
                                    {
                                        //* means to the end of the range
                                        rangehigh = -1;
                                    }
                                    break;
                                }
                            }
    
                            //load the group members now
                            Log.debug("next range will be {}-{}",oldrangehigh,rangehigh!=-1?rangehigh:"*");
    
                            tmpGroup=processGroup(ctx, attrs, membersToIgnore);
                            if (tmpGroup!=null&& !tmpGroup.getMembers().isEmpty())
                            {
                                members.addAll(tmpGroup.getMembers());
                            }
                            else
                            {
                                // no next found
                                break;
                            }
    
                        }
                        catch (Exception e)
                        {
                            Log.debug("error while reading the ldap group with range retrieval",e); // no next found, cause of missing attribute
                            break;
                        }
                    }while (rangehigh!=-1);  //The last part was received
    
                    return new Group(name, description, members, admins);
                }
            }
        }
        finally {
            try {
                if (ctx != null) {
                    ctx.setRequestControls(null);
                    ctx.close();
                }
            }
            catch (Exception ex) {
                Log.debug( "An exception was ignored while trying to close the Ldap context after trying to get a group.", ex );
            }
        }
    }
Reads the group with the given DN

@param groupDN         the absolute DN of the group
@param membersToIgnore A mutable set of DNs and/or UIDs (for Posix mode) to ignore. This set will be
                       filled with visited DNs. If flatten of hierarchies of groups is active
                       ({@link LdapManager#isFlattenNestedGroups()}, this will prevent endless loops
                       for cyclic hierarchies.
@return A group (never null)
@throws NamingException When a group can't be read from LDAP.
xmppserver/src/main/java/org/jivesoftware/openfire/ldap/LdapGroupProvider.java