Commit 39a5e528 authored by Matt Tucker's avatar Matt Tucker Committed by matt

Added pagination support to search results (JM-247).


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@1213 b35dd754-fafc-0310-a699-88a17e54d16e
parent 04cf830e
...@@ -218,8 +218,13 @@ public class LdapUserProvider implements UserProvider { ...@@ -218,8 +218,13 @@ public class LdapUserProvider implements UserProvider {
} }
// Otherwise, only read in certain results. // Otherwise, only read in certain results.
else { else {
for (int i = 0; i < startIndex; i++) { for (int i=0; i < startIndex; i++) {
answer.next(); if (answer.hasMoreElements()) {
answer.next();
}
else {
return Collections.emptyList();
}
} }
// Now read in desired number of results (or stop if we run out of results). // Now read in desired number of results (or stop if we run out of results).
for (int i = 0; i < numResults; i++) { for (int i = 0; i < numResults; i++) {
...@@ -345,6 +350,86 @@ public class LdapUserProvider implements UserProvider { ...@@ -345,6 +350,86 @@ public class LdapUserProvider implements UserProvider {
return new UserCollection((String[])usernames.toArray(new String[usernames.size()])); return new UserCollection((String[])usernames.toArray(new String[usernames.size()]));
} }
public Collection<User> findUsers(Set<String> fields, String query, int startIndex,
int numResults) throws UnsupportedOperationException
{
if (fields.isEmpty()) {
return Collections.emptyList();
}
if (!searchFields.keySet().containsAll(fields)) {
throw new IllegalArgumentException("Search fields " + fields + " are not valid.");
}
List<String> usernames = new ArrayList<String>();
LdapContext ctx = null;
try {
ctx = manager.getContext();
// Sort on username field.
Control[] searchControl = new Control[]{
new SortControl(new String[]{manager.getUsernameField()}, Control.NONCRITICAL)
};
ctx.setRequestControls(searchControl);
// Search for the dn based on the username.
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
constraints.setReturningAttributes(new String[] { manager.getUsernameField() });
StringBuilder filter = new StringBuilder();
if (fields.size() > 1) {
filter.append("(|");
}
for (String field:fields) {
String attribute = searchFields.get(field);
filter.append("(").append(attribute).append("=").append(query).append(")");
}
if (fields.size() > 1) {
filter.append(")");
}
// TODO: used paged results is supported by LDAP server.
NamingEnumeration answer = ctx.search("", filter.toString(), constraints);
for (int i=0; i < startIndex; i++) {
if (answer.hasMoreElements()) {
answer.next();
}
else {
return Collections.emptyList();
}
}
// Now read in desired number of results (or stop if we run out of results).
for (int i = 0; i < numResults; i++) {
if (answer.hasMoreElements()) {
// Get the next userID.
usernames.add(
(String)((SearchResult)answer.next()).getAttributes().get(
manager.getUsernameField()).get()
);
}
else {
break;
}
}
// If client-side sorting is enabled, sort.
if (Boolean.valueOf(JiveGlobals.getXMLProperty(
"ldap.clientSideSorting")).booleanValue())
{
Collections.sort(usernames);
}
}
catch (Exception e) {
Log.error(e);
}
finally {
try {
if (ctx != null) {
ctx.setRequestControls(null);
ctx.close();
}
}
catch (Exception ignored) { }
}
return new UserCollection((String[])usernames.toArray(new String[usernames.size()]));
}
public boolean isReadOnly() { public boolean isReadOnly() {
return true; return true;
} }
......
...@@ -227,18 +227,11 @@ public class DefaultUserProvider implements UserProvider { ...@@ -227,18 +227,11 @@ public class DefaultUserProvider implements UserProvider {
pstmt = con.prepareStatement(ALL_USERS); pstmt = con.prepareStatement(ALL_USERS);
ResultSet rs = pstmt.executeQuery(); ResultSet rs = pstmt.executeQuery();
DbConnectionManager.setFetchSize(rs, startIndex + numResults); DbConnectionManager.setFetchSize(rs, startIndex + numResults);
// Move to start of index DbConnectionManager.scrollResultSet(rs, startIndex);
for (int i = 0; i < startIndex; i++) { int count = 0;
rs.next(); while (rs.next() && count < numResults) {
} usernames.add(rs.getString(1));
// Now read in desired number of results (or stop if we run out of results). count++;
for (int i = 0; i < numResults; i++) {
if (rs.next()) {
usernames.add(rs.getString(1));
}
else {
break;
}
} }
rs.close(); rs.close();
} }
...@@ -450,6 +443,72 @@ public class DefaultUserProvider implements UserProvider { ...@@ -450,6 +443,72 @@ public class DefaultUserProvider implements UserProvider {
return new UserCollection((String[])usernames.toArray(new String[usernames.size()])); return new UserCollection((String[])usernames.toArray(new String[usernames.size()]));
} }
public Collection<User> findUsers(Set<String> fields, String query, int startIndex,
int numResults) throws UnsupportedOperationException
{
if (fields.isEmpty()) {
return Collections.emptyList();
}
if (!getSearchFields().containsAll(fields)) {
throw new IllegalArgumentException("Search fields " + fields + " are not valid.");
}
// SQL LIKE queries don't map directly into a keyword/wildcard search like we want.
// Therefore, we do a best approximiation by replacing '*' with '%' and then
// surrounding the whole query with two '%'. This will return more data than desired,
// but is better than returning less data than desired.
query = "%" + query.replace('*', '%') + "%";
if (query.endsWith("%%")) {
query = query.substring(0, query.length()-1);
}
List<String> usernames = new ArrayList<String>(50);
Connection con = null;
Statement stmt = null;
try {
con = DbConnectionManager.getConnection();
stmt = con.createStatement();
StringBuilder sql = new StringBuilder();
sql.append("SELECT username FROM jiveUser WHERE");
boolean first = true;
if (fields.contains("Username")) {
sql.append(" username LIKE '").append(StringUtils.escapeForSQL(query)).append("'");
first = false;
}
if (fields.contains("Name")) {
if (!first) {
sql.append(" AND");
}
sql.append(" name LIKE '").append(StringUtils.escapeForSQL(query)).append("'");
first = false;
}
if (fields.contains("Email")) {
if (!first) {
sql.append(" AND");
}
sql.append(" email LIKE '").append(StringUtils.escapeForSQL(query)).append("'");
}
ResultSet rs = stmt.executeQuery(sql.toString());
// Scroll to the start index.
DbConnectionManager.scrollResultSet(rs, startIndex);
int count = 0;
while (rs.next() && count < numResults) {
usernames.add(rs.getString(1));
count++;
}
rs.close();
}
catch (SQLException e) {
Log.error(e);
}
finally {
try { if (stmt != null) { stmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
return new UserCollection((String[])usernames.toArray(new String[usernames.size()]));
}
public boolean isReadOnly() { public boolean isReadOnly() {
return false; return false;
} }
......
...@@ -194,6 +194,32 @@ public interface UserProvider { ...@@ -194,6 +194,32 @@ public interface UserProvider {
public Collection<User> findUsers(Set<String> fields, String query) public Collection<User> findUsers(Set<String> fields, String query)
throws UnsupportedOperationException; throws UnsupportedOperationException;
/**
* 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".<p>
*
* 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.<p>
*
* This method should throw an UnsupportedOperationException if this
* operation is not supported by the backend user store.
*
* @param fields the fields to search on.
* @param query the query string.
* @return a Collection of users that match the search.
* @return startIndex the starting index in the search result to return.
* @return numResults the number of users to return in the search result.
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
*/
public Collection<User> findUsers(Set<String> fields, String query, int startIndex,
int numResults) throws UnsupportedOperationException;
/** /**
* Returns true if the UserProvider is read-only. When read-only, that means that * Returns true if the UserProvider is read-only. When read-only, that means that
* users can not be created, deleted, or modified. * users can not be created, deleted, or modified.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment