@Override
    public Collection<String> search(String query, int startIndex, int numResults) {
        if (query == null || query.isEmpty()) {
            return Collections.emptyList();
        }
        // SQL LIKE queries don't map directly into a keyword/wildcard search like we want.
        // Therefore, we do a best approximation by replacing '*' with '%' and then
        // surrounding the whole query with two '%'. This will return more data than desired,
        // but is better than returning fewer data than desired.
        query = "%" + query.replace('*', '%') + "%";
        if (query.endsWith("%%")) {
            query = query.substring(0, query.length()-1);
        }

        List<String> groupNames = new ArrayList<>();
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            con = DbConnectionManager.getConnection();
            if ((startIndex==0) && (numResults==Integer.MAX_VALUE))
            {
               pstmt = con.prepareStatement(SEARCH_GROUP_NAME);
               pstmt.setString(1, query);
               rs = pstmt.executeQuery();
               while (rs.next()) {
                   groupNames.add(rs.getString(1));
               }
            } else {
               pstmt = DbConnectionManager.createScrollablePreparedStatement(con, SEARCH_GROUP_NAME);
               DbConnectionManager.limitRowsAndFetchSize(pstmt, startIndex, numResults);
               pstmt.setString(1, query);
               rs = pstmt.executeQuery();
               // Scroll to the start index.
               DbConnectionManager.scrollResultSet(rs, startIndex);
               int count = 0;
               while (rs.next() && count < numResults) {
                   groupNames.add(rs.getString(1));
                   count++;
               }	
            }
        }
        catch (SQLException e) {
            Log.error(e.getMessage(), e);
        }
        finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        return groupNames;
    }
Database implementation of the GroupManager interface.

@author Matt Tucker
xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java