@Override
            public Iterator<String> getFeatures(String name, String node, JID senderJID) {
                if (node != null && serverNodeProviders.get(node) != null) {
                    // Redirect the request to the disco info provider of the specified node
                    return serverNodeProviders.get(node).getFeatures(name, node, senderJID);
                }
                if (name == null || name.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
                    // Answer features of the server itself.
                    final Set<String> result = new HashSet<>(serverFeatures.keySet());

                    if ( !UserManager.getInstance().isRegisteredUser( senderJID, false ) ) {
                        // Remove features not available to users from other servers or anonymous users.
                        // TODO this should be determined dynamically.
                        result.remove(IQPrivateHandler.NAMESPACE);
                        result.remove(IQBlockingHandler.NAMESPACE);
                    }
                    return result.iterator();
                }
                else if (node != null) {
                    return XMPPServer.getInstance().getIQPEPHandler().getFeatures(name, node, senderJID);
                }
                else {
                    // Answer with features of users of the server.
                    final Collection<UserFeaturesProvider> providers;
                    if (SessionManager.getInstance().isAnonymousClientSession(name))
                    {
                        // Answer features of an anonymous user.
                        providers = anonymousUserFeatureProviders;
                    }
                    else
                    {
                        // Answer features of a registered user.
                        // Note: We know that this user exists because #hasInfo returned true
                        providers = registeredUserFeatureProviders;
                    }
                    final Set<String> result = new HashSet<>();
                    for ( final UserFeaturesProvider provider : providers )
                    {
                        final Iterator<String> features = provider.getFeatures();
                        while ( features.hasNext() )
                        {
                            result.add( features.next() );
                        }
                    }
                    return result.iterator();
                }
            }
Returns the DiscoInfoProvider responsible for providing information at the server level. This
means that this DiscoInfoProvider will provide information whenever a disco request whose
recipient JID is the server (e.g. localhost) is made.

@return the DiscoInfoProvider responsible for providing information at the server level.
xmppserver/src/main/java/org/jivesoftware/openfire/disco/IQDiscoInfoHandler.java