@Override
    public Collection<User> findUsers( Set<String> fields, String query, int startIndex, int numResults ) throws UnsupportedOperationException
    {
        final List<User> userList = new ArrayList<>();
        int supportSearch = getUserProviders().size();
        int totalMatchedUserCount = 0;

        for ( final UserProvider provider : getUserProviders() )
        {
            try
            {
                // Use only those fields that are supported by the provider.
                final Set<String> supportedFields = new HashSet<>( fields );
                supportedFields.retainAll( provider.getSearchFields() );

                // Query the provider for sub-results.
                final Collection<User> providerResults = provider.findUsers( supportedFields, query );

                // Keep track of how many hits we have had so far.
                totalMatchedUserCount += providerResults.size();

                // Check if this sub-result contains the start of the page of data that is searched for.
                if ( startIndex >= totalMatchedUserCount )
                {
                    continue;
                }

                // From the sub-results, take those that are of interest.
                final int providerStartIndex = Math.max( 0, startIndex - totalMatchedUserCount );
                final int providerResultMax = numResults - userList.size();
                final List<User> providerList = providerResults instanceof List<?> ?
                        (List<User>) providerResults : new ArrayList<>( providerResults );
                userList.addAll( providerList.subList( providerStartIndex, Math.min( providerList.size(), providerResultMax ) ));

                // Check if we have enough results.
                if ( userList.size() >= numResults )
                {
                    break;
                }
            }
            catch ( UnsupportedOperationException uoe )
            {
                Log.warn( "UserProvider.findUsers is not supported by this UserProvider: " + provider.getClass().getName() );
                supportSearch--;
            }
        }

        if ( supportSearch == 0 )
        {
            throw new UnsupportedOperationException( "None of the backing providers support this operation." );
        }
        return userList;
    }
Searches for users based on a set of fields and a query string. The fields must  be taken from the values
returned by {@link #getSearchFields()}. The query can  include wildcards. For example, a search on the field
"Name" with a query of "Ma*"  might return user's with the name "Matt", "Martha" and "Madeline".

This method throws an UnsupportedOperationException when none of the backing providers support search.

When fields are provided that are not supported by a particular provider, those fields are ignored by that
provider (but can still be used by other providers).

The startIndex and numResults parameters are used to page through search results. For example, if the startIndex
is 0 and numResults is 10, the first  10 search results will be returned. Note that numResults is a request for
the number of results to return and that the actual number of results returned may be fewer.

@param fields     the fields to search on.
@param query      the query string.
@param startIndex the starting index in the search result to return.
@param numResults the number of users to return in the search result.
@return a Collection of users that match the search.
@throws UnsupportedOperationException When none of the providers support search.
xmppserver/src/main/java/org/jivesoftware/openfire/user/UserMultiProvider.java