Commit 34ed8456 authored by Tom Evans's avatar Tom Evans Committed by tevans

OF-731: Rework HybridUserProvider to address multiple issues reported via Ignite community

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13925 b35dd754-fafc-0310-a699-88a17e54d16e
parent cb6bdeba
...@@ -13,30 +13,16 @@ ...@@ -13,30 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* *
* HybridUserProvider.java
*
* Created on 16. April 2007, 21:48
* by Marc Seeger
* code works fine as far as my 10 User Test-Server goes
* It basically checks different userproviders which are being set in the configuration xml file
* I use it in combination with hybridauth providers to be able to get the usual users from ldap but still have some Bots in MySQL
*
* Changed on 14. Nov. 2007, 10:48
* by Chris Neasbitt
* -changed getUsers(int startIndex, int numResults) method to return a subset of the total users from all providers
* -changed the getUsers() method to use a vector internally since addAll is an optional method of the collection
* interface we cannot assume that all classes that support the collection interface also support the addAll method
* -changed the getUserCount() method to iterate through an array of providers while calling a private helper method
* getUserCount(UserProvider provider) on each of them.
*/ */
package org.jivesoftware.openfire.user; package org.jivesoftware.openfire.user;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.Vector;
import org.jivesoftware.util.ClassUtils; import org.jivesoftware.util.ClassUtils;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
...@@ -44,405 +30,246 @@ import org.slf4j.Logger; ...@@ -44,405 +30,246 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Delegate UserProvider operations among up to three configurable provider implementation classes.
*
* @author Marc Seeger * @author Marc Seeger
* @author Chris Neasbitt * @author Chris Neasbitt
* @author Tom Evans
*/ */
public class HybridUserProvider implements UserProvider { public class HybridUserProvider implements UserProvider {
private static final Logger Log = LoggerFactory.getLogger(HybridUserProvider.class); private static final Logger Log = LoggerFactory.getLogger(HybridUserProvider.class);
private UserProvider primaryProvider = null; private List<UserProvider> userproviders = null;
private UserProvider secondaryProvider = null;
private UserProvider tertiaryProvider = null;
private UserProvider[] userproviders = {primaryProvider, secondaryProvider, tertiaryProvider};
private Set<String> primaryOverrides = new HashSet<String>(); public HybridUserProvider() {
private Set<String> secondaryOverrides = new HashSet<String>();
private Set<String> tertiaryOverrides = new HashSet<String>();
// Migrate user provider properties
JiveGlobals.migrateProperty("hybridUserProvider.primaryProvider.className");
JiveGlobals.migrateProperty("hybridUserProvider.secondaryProvider.className");
JiveGlobals.migrateProperty("hybridUserProvider.tertiaryProvider.className");
public HybridUserProvider() { userproviders = new ArrayList<UserProvider>();
// Load primary, secondary, and tertiary user providers.
String primaryClass = JiveGlobals.getXMLProperty("hybridUserProvider.primaryProvider.className"); // Load primary, secondary, and tertiary user providers.
String primaryClass = JiveGlobals.getProperty("hybridUserProvider.primaryProvider.className");
if (primaryClass == null) { if (primaryClass == null) {
Log.error("A primary UserProvider must be specified in the openfire.xml."); Log.error("A primary UserProvider must be specified via openfire.xml or the system properties");
return; return;
} }
try { try {
Class c = ClassUtils.forName(primaryClass); Class c = ClassUtils.forName(primaryClass);
primaryProvider = (UserProvider) c.newInstance(); UserProvider primaryProvider = (UserProvider) c.newInstance();
userproviders.add(primaryProvider);
Log.debug("Primary user provider: " + primaryClass); Log.debug("Primary user provider: " + primaryClass);
} catch (Exception e) { } catch (Exception e) {
Log.error("Unable to load primary user provider: " + primaryClass + Log.error("Unable to load primary user provider: " + primaryClass +
". Users in this provider will be disabled.", e); ". Users in this provider will be disabled.", e);
return; return;
} }
String secondaryClass = JiveGlobals.getXMLProperty("hybridUserProvider.secondaryProvider.className"); String secondaryClass = JiveGlobals.getProperty("hybridUserProvider.secondaryProvider.className");
if (secondaryClass != null) { if (secondaryClass != null) {
try { try {
Class c = ClassUtils.forName(secondaryClass); Class c = ClassUtils.forName(secondaryClass);
secondaryProvider = (UserProvider) c.newInstance(); UserProvider secondaryProvider = (UserProvider) c.newInstance();
userproviders.add(secondaryProvider);
Log.debug("Secondary user provider: " + secondaryClass); Log.debug("Secondary user provider: " + secondaryClass);
} catch (Exception e) { } catch (Exception e) {
Log.error("Unable to load secondary user provider: " + secondaryClass, e); Log.error("Unable to load secondary user provider: " + secondaryClass, e);
} }
} }
String tertiaryClass = JiveGlobals.getXMLProperty("hybridUserProvider.tertiaryProvider.className"); String tertiaryClass = JiveGlobals.getProperty("hybridUserProvider.tertiaryProvider.className");
if (tertiaryClass != null) { if (tertiaryClass != null) {
try { try {
Class c = ClassUtils.forName(tertiaryClass); Class c = ClassUtils.forName(tertiaryClass);
tertiaryProvider = (UserProvider) c.newInstance(); UserProvider tertiaryProvider = (UserProvider) c.newInstance();
userproviders.add(tertiaryProvider);
Log.debug("Tertiary user provider: " + tertiaryClass); Log.debug("Tertiary user provider: " + tertiaryClass);
} catch (Exception e) { } catch (Exception e) {
Log.error("Unable to load tertiary user provider: " + tertiaryClass, e); Log.error("Unable to load tertiary user provider: " + tertiaryClass, e);
} }
} }
// Now, load any overrides.
String overrideList = JiveGlobals.getXMLProperty(
"hybridUserProvider.primaryProvider.overrideList", "");
for (String user : overrideList.split(",")) {
primaryOverrides.add(user.trim().toLowerCase());
}
if (secondaryProvider != null) {
overrideList = JiveGlobals.getXMLProperty(
"hybridUserProvider.secondaryProvider.overrideList", "");
for (String user : overrideList.split(",")) {
secondaryOverrides.add(user.trim().toLowerCase());
}
}
if (tertiaryProvider != null) {
overrideList = JiveGlobals.getXMLProperty(
"hybridUserProvider.tertiaryProvider.overrideList", "");
for (String user : overrideList.split(",")) {
tertiaryOverrides.add(user.trim().toLowerCase());
}
}
} }
public User createUser(String username, String password, String name, String email) throws UserAlreadyExistsException { public User createUser(String username, String password, String name, String email) throws UserAlreadyExistsException {
//initialize our returnvalue
User returnvalue = null;
//try to use the providers to create a user and change the return value to that user
if (!primaryProvider.isReadOnly()) {
try {
returnvalue = primaryProvider.createUser(username, password, name, email);
}
finally {
}
} else if (secondaryProvider != null) { User returnvalue = null;
if (!secondaryProvider.isReadOnly()) {
try {
returnvalue = secondaryProvider.createUser(username, password, name, email);
}
finally {
}
} // create the user (first writable provider wins)
} else if (tertiaryProvider != null) { for (UserProvider provider : userproviders) {
if (!tertiaryProvider.isReadOnly()) { if (provider.isReadOnly()) {
try { continue;
returnvalue = tertiaryProvider.createUser(username, password, name, email); }
} returnvalue = provider.createUser(username, password, name, email);
if (returnvalue != null) {
finally { break;
} }
}
} }
//return our created user if (returnvalue == null) {
if (returnvalue != null) { throw new UnsupportedOperationException();
return returnvalue;
} else {
throw new UnsupportedOperationException();
} }
return returnvalue;
} }
public void deleteUser(String username) { public void deleteUser(String username) {
if (!primaryProvider.isReadOnly()) {
try {
primaryProvider.deleteUser(username);
return;
}
finally {
}
} else if (secondaryProvider != null) { boolean isDeleted = false;
if (!secondaryProvider.isReadOnly()) {
try {
secondaryProvider.deleteUser(username);
return;
}
finally { for (UserProvider provider : userproviders) {
} if (provider.isReadOnly()) {
continue;
} }
} else if (tertiaryProvider != null) { provider.deleteUser(username);
if (!tertiaryProvider.isReadOnly()) { isDeleted = true;
try { }
tertiaryProvider.deleteUser(username);
return;
}
finally {
}
} else {
// Reject the operation since all of the providers seem to be read-only
throw new UnsupportedOperationException();
}
} // all providers are read-only
if (!isDeleted) {
throw new UnsupportedOperationException();
}
} }
public Collection<User> findUsers(Set<String> fields, String query) throws UnsupportedOperationException { public Collection<User> findUsers(Set<String> fields, String query) throws UnsupportedOperationException {
List<User> userList = new ArrayList<User>();
Collection<User> returnvalue = null; boolean isUnsupported = false;
try {
returnvalue = primaryProvider.findUsers(fields, query); for (UserProvider provider : userproviders) {
}
// validate search fields for each provider
finally { Set<String> validFields = provider.getSearchFields();
} for (String field : fields) {
if (!validFields.contains(field)) {
if (secondaryProvider != null) { continue;
try { }
}
returnvalue = secondaryProvider.findUsers(fields, query);
} try {
userList.addAll(provider.findUsers(fields, query));
finally { } catch (UnsupportedOperationException uoe) {
} Log.warn("UserProvider.findUsers is not supported by this UserProvider: " + provider.getClass().getName());
} isUnsupported = true;
if (tertiaryProvider != null) { }
try { }
returnvalue = tertiaryProvider.findUsers(fields, query);
} if (isUnsupported && userList.size() == 0) {
throw new UnsupportedOperationException();
finally { }
} return userList;
}
//return our collection of users
if (returnvalue != null) {
return returnvalue;
} else {
throw new UnsupportedOperationException();
}
} }
public Collection<User> findUsers(Set<String> fields, String query, int startIndex, int numResults) throws UnsupportedOperationException { public Collection<User> findUsers(Set<String> fields, String query, int startIndex, int numResults) throws UnsupportedOperationException {
Collection<User> returnvalue = null;
try {
returnvalue = primaryProvider.findUsers(fields, query, startIndex, numResults);
}
finally {
}
if (secondaryProvider != null) {
try {
returnvalue = secondaryProvider.findUsers(fields, query, startIndex, numResults);
}
finally {
}
}
if (tertiaryProvider != null) {
try {
returnvalue = tertiaryProvider.findUsers(fields, query, startIndex, numResults);
}
finally {
}
}
//return our Collection of Users List<User> userList = new ArrayList<User>();
if (returnvalue != null) { boolean isUnsupported = false;
return returnvalue; int totalMatchedUserCount = 0;
} else {
throw new UnsupportedOperationException(); for (UserProvider provider : userproviders) {
}
// validate search fields for each provider
Set<String> validFields = provider.getSearchFields();
for (String field : fields) {
if (!validFields.contains(field)) {
continue;
}
}
try {
Collection<User> providerResults = provider.findUsers(fields, query);
totalMatchedUserCount += providerResults.size();
if (startIndex >= totalMatchedUserCount) {
continue;
}
int providerStartIndex = Math.max(0, startIndex - totalMatchedUserCount);
int providerResultMax = numResults - userList.size();
List<User> providerList = providerResults instanceof List<?> ?
(List<User>) providerResults : new ArrayList<User>(providerResults);
userList.addAll(providerList.subList(providerStartIndex, providerResultMax));
if (userList.size() >= numResults) {
break;
}
} catch (UnsupportedOperationException uoe) {
Log.warn("UserProvider.findUsers is not supported by this UserProvider: " + provider.getClass().getName());
isUnsupported = true;
}
}
if (isUnsupported && userList.size() == 0) {
throw new UnsupportedOperationException();
}
return userList;
} }
public Set<String> getSearchFields() throws UnsupportedOperationException { public Set<String> getSearchFields() throws UnsupportedOperationException {
Set<String> returnvalue = null;
try {
returnvalue = primaryProvider.getSearchFields();
}
finally {
}
if (secondaryProvider != null) {
try {
returnvalue = secondaryProvider.getSearchFields(); Set<String> returnvalue = new HashSet<String>();
}
finally { for (UserProvider provider : userproviders) {
} returnvalue.addAll(provider.getSearchFields());
}
if (tertiaryProvider != null) {
try {
returnvalue = tertiaryProvider.getSearchFields();
}
finally {
}
} }
//return our Set of Strings // no search fields were returned
if (returnvalue != null) { if (returnvalue.size() == 0) {
return returnvalue;
} else {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
return returnvalue;
} }
public int getUserCount() { public int getUserCount() {
int count = 0; int count = 0;
for (UserProvider provider : userproviders) { for (UserProvider provider : userproviders) {
count = count + this.getUserCount(provider); count += provider.getUserCount();
} }
return count; return count;
} }
private int getUserCount(UserProvider provider) {
int returnvalue = 0;
if (provider != null) {
try {
returnvalue = returnvalue + provider.getUserCount();
}
finally {
}
}
return returnvalue;
}
public Collection<String> getUsernames() { public Collection<String> getUsernames() {
Collection<String> returnvalue = null;
try {
returnvalue = primaryProvider.getUsernames();
}
finally { List<String> returnvalue = new ArrayList<String>();
}
if (secondaryProvider != null) {
try {
returnvalue.addAll(secondaryProvider.getUsernames());
}
finally { for (UserProvider provider : userproviders){
} returnvalue.addAll(provider.getUsernames());
}
if (tertiaryProvider != null) {
try {
returnvalue.addAll(tertiaryProvider.getUsernames());
}
finally {
}
}
//return our Set of Strings
if (returnvalue != null) {
return returnvalue;
} else {
throw new UnsupportedOperationException();
} }
return returnvalue;
} }
public Collection<User> getUsers() { public Collection<User> getUsers() {
Vector<User> returnvalue = null; List<User> returnvalue = new ArrayList<User>();
try {
returnvalue = new Vector<User>(primaryProvider.getUsers());
}
finally {
}
if (secondaryProvider != null) {
try {
returnvalue.addAll(secondaryProvider.getUsers());
}
finally {
}
}
if (tertiaryProvider != null) {
try {
returnvalue.addAll(tertiaryProvider.getUsers());
}
finally { for (UserProvider provider : userproviders){
} returnvalue.addAll(provider.getUsers());
} }
//return our Set of Strings return returnvalue;
if (returnvalue != null) {
return returnvalue;
} else {
throw new UnsupportedOperationException();
}
} }
/*
*Changed by Chris Neasbitt to more accurately represent the intent of the method
*
*This method now removes a sub set of the combined users from all providers. This
*is done in places as to avoid copying collections of users in memory.
*/
public Collection<User> getUsers(int startIndex, int numResults) { public Collection<User> getUsers(int startIndex, int numResults) {
Vector<User> returnresult = new Vector<User>();
int numResultsLeft = numResults;
int currentStartIndex = startIndex;
for (UserProvider provider : userproviders) {
if (numResultsLeft == 0) {
break;
}
int pusercount = this.getUserCount(provider);
if (pusercount == 0 || currentStartIndex >= pusercount) {
currentStartIndex = currentStartIndex - pusercount;
continue;
} else {
Collection<User> subresult = provider.getUsers(currentStartIndex, numResultsLeft); List<User> userList = new ArrayList<User>();
currentStartIndex = currentStartIndex - subresult.size(); int totalUserCount = 0;
numResultsLeft = numResultsLeft - subresult.size();
returnresult.addAll(subresult); for (UserProvider provider : userproviders) {
} int providerStartIndex = Math.max((startIndex - totalUserCount), 0);
} totalUserCount += provider.getUserCount();
if (startIndex >= totalUserCount) {
return returnresult; continue;
}
int providerResultMax = numResults - userList.size();
userList.addAll(provider.getUsers(providerStartIndex, providerResultMax));
if (userList.size() >= numResults) {
break;
}
}
return userList;
} }
public boolean isReadOnly() { public boolean isReadOnly() {
...@@ -458,163 +285,128 @@ public class HybridUserProvider implements UserProvider { ...@@ -458,163 +285,128 @@ public class HybridUserProvider implements UserProvider {
} }
public User loadUser(String username) throws UserNotFoundException { public User loadUser(String username) throws UserNotFoundException {
try {
return primaryProvider.loadUser(username);
}
catch (Exception e) {
}
if (secondaryProvider != null) {
try {
return secondaryProvider.loadUser(username); for (UserProvider provider : userproviders) {
} try {
return provider.loadUser(username);
catch (Exception e) { }
} catch (UserNotFoundException unfe) {
} if (Log.isDebugEnabled()) {
Log.debug("User " + username + " not found by UserProvider " + provider.getClass().getName());
}
if (tertiaryProvider != null) { }
try { }
return tertiaryProvider.loadUser(username); //if we get this far, no provider was able to load the user
}
catch (Exception e) {
}
}
//if we get this far, no provider seems to successfully have loaded the user
throw new UserNotFoundException(); throw new UserNotFoundException();
} }
public void setCreationDate(String username, Date creationDate) throws UserNotFoundException { public void setCreationDate(String username, Date creationDate) throws UserNotFoundException {
if (primaryProvider != null)
try {
primaryProvider.setCreationDate(username, creationDate);
return;
} catch (Exception e) {
}
if (secondaryProvider != null) {
try {
secondaryProvider.setCreationDate(username, creationDate);
return;
}
catch (Exception e) {
}
}
if (tertiaryProvider != null) {
try {
tertiaryProvider.setCreationDate(username, creationDate);
return;
}
catch (Exception e) {
throw new UserNotFoundException();
}
}
boolean isUnsupported = false;
for (UserProvider provider : userproviders) {
try {
provider.setCreationDate(username, creationDate);
return;
}
catch (UnsupportedOperationException uoe) {
Log.warn("UserProvider.setCreationDate is not supported by this UserProvider: " + provider.getClass().getName());
isUnsupported = true;
}
catch (UserNotFoundException unfe) {
if (Log.isDebugEnabled()) {
Log.debug("User " + username + " not found by UserProvider " + provider.getClass().getName());
}
}
}
if (isUnsupported) {
throw new UnsupportedOperationException();
}
else {
throw new UserNotFoundException();
}
} }
public void setEmail(String username, String email) throws UserNotFoundException { public void setEmail(String username, String email) throws UserNotFoundException {
if (primaryProvider != null)
try {
primaryProvider.setEmail(username, email);
return;
} catch (Exception e) {
}
if (secondaryProvider != null) {
try {
secondaryProvider.setEmail(username, email);
return;
}
catch (Exception e) {
}
}
if (tertiaryProvider != null) {
try {
tertiaryProvider.setEmail(username, email);
return;
}
catch (Exception e) {
throw new UserNotFoundException();
}
}
boolean isUnsupported = false;
for (UserProvider provider : userproviders) {
try {
provider.setEmail(username, email);
return;
}
catch (UnsupportedOperationException uoe) {
Log.warn("UserProvider.setEmail is not supported by this UserProvider: " + provider.getClass().getName());
isUnsupported = true;
}
catch (UserNotFoundException unfe) {
if (Log.isDebugEnabled()) {
Log.debug("User " + username + " not found by UserProvider " + provider.getClass().getName());
}
}
}
if (isUnsupported) {
throw new UnsupportedOperationException();
}
else {
throw new UserNotFoundException();
}
} }
public void setModificationDate(String username, Date modificationDate) throws UserNotFoundException { public void setModificationDate(String username, Date modificationDate) throws UserNotFoundException {
//without it eclipse goes apeshit boolean isUnsupported = false;
if (primaryProvider != null)
//apeshit I say! for (UserProvider provider : userproviders) {
try {
provider.setModificationDate(username, modificationDate);
try { return;
primaryProvider.setModificationDate(username, modificationDate); }
return; catch (UnsupportedOperationException uoe) {
} catch (Exception e) { Log.warn("UserProvider.setModificationDate is not supported by this UserProvider: " + provider.getClass().getName());
} isUnsupported = true;
}
if (secondaryProvider != null) { catch (UserNotFoundException unfe) {
try { if (Log.isDebugEnabled()) {
secondaryProvider.setModificationDate(username, modificationDate); Log.debug("User " + username + " not found by UserProvider " + provider.getClass().getName());
return; }
} }
}
catch (Exception e) { if (isUnsupported) {
} throw new UnsupportedOperationException();
} }
if (tertiaryProvider != null) { else {
try { throw new UserNotFoundException();
tertiaryProvider.setModificationDate(username, modificationDate); }
return;
}
catch (Exception e) {
throw new UserNotFoundException();
}
}
} }
public void setName(String username, String name) throws UserNotFoundException { public void setName(String username, String name) throws UserNotFoundException {
if (primaryProvider != null)
try {
primaryProvider.setName(username, name);
return;
} catch (Exception e) {
}
if (secondaryProvider != null) { boolean isUnsupported = false;
try {
secondaryProvider.setName(username, name); for (UserProvider provider : userproviders) {
return; try {
} provider.setName(username, name);
return;
catch (Exception e) { }
} catch (UnsupportedOperationException uoe) {
} Log.warn("UserProvider.setName is not supported by this UserProvider: " + provider.getClass().getName());
if (tertiaryProvider != null) { isUnsupported = true;
try { }
tertiaryProvider.setName(username, name); catch (UserNotFoundException unfe) {
return; if (Log.isDebugEnabled()) {
} Log.debug("User " + username + " not found by UserProvider " + provider.getClass().getName());
}
catch (Exception e) { }
throw new UserNotFoundException(); }
} if (isUnsupported) {
} throw new UnsupportedOperationException();
}
else {
throw new UserNotFoundException();
}
} }
} }
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