/* * Copyright (C) 2004-2009 Jive Software. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.jivesoftware.openfire.user; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import org.jivesoftware.util.ClassUtils; import org.jivesoftware.util.JiveGlobals; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Delegate UserProvider operations among up to three configurable provider implementation classes. * * @author Marc Seeger * @author Chris Neasbitt * @author Tom Evans */ public class HybridUserProvider implements UserProvider { private static final Logger Log = LoggerFactory.getLogger(HybridUserProvider.class); private List<UserProvider> userproviders = null; public HybridUserProvider() { // Migrate user provider properties JiveGlobals.migrateProperty("hybridUserProvider.primaryProvider.className"); JiveGlobals.migrateProperty("hybridUserProvider.secondaryProvider.className"); JiveGlobals.migrateProperty("hybridUserProvider.tertiaryProvider.className"); userproviders = new ArrayList<UserProvider>(); // Load primary, secondary, and tertiary user providers. String primaryClass = JiveGlobals.getProperty("hybridUserProvider.primaryProvider.className"); if (primaryClass == null) { Log.error("A primary UserProvider must be specified via openfire.xml or the system properties"); return; } try { Class c = ClassUtils.forName(primaryClass); UserProvider primaryProvider = (UserProvider) c.newInstance(); userproviders.add(primaryProvider); Log.debug("Primary user provider: " + primaryClass); } catch (Exception e) { Log.error("Unable to load primary user provider: " + primaryClass + ". Users in this provider will be disabled.", e); return; } String secondaryClass = JiveGlobals.getProperty("hybridUserProvider.secondaryProvider.className"); if (secondaryClass != null) { try { Class c = ClassUtils.forName(secondaryClass); UserProvider secondaryProvider = (UserProvider) c.newInstance(); userproviders.add(secondaryProvider); Log.debug("Secondary user provider: " + secondaryClass); } catch (Exception e) { Log.error("Unable to load secondary user provider: " + secondaryClass, e); } } String tertiaryClass = JiveGlobals.getProperty("hybridUserProvider.tertiaryProvider.className"); if (tertiaryClass != null) { try { Class c = ClassUtils.forName(tertiaryClass); UserProvider tertiaryProvider = (UserProvider) c.newInstance(); userproviders.add(tertiaryProvider); Log.debug("Tertiary user provider: " + tertiaryClass); } catch (Exception e) { Log.error("Unable to load tertiary user provider: " + tertiaryClass, e); } } } public User createUser(String username, String password, String name, String email) throws UserAlreadyExistsException { User returnvalue = null; // create the user (first writable provider wins) for (UserProvider provider : userproviders) { if (provider.isReadOnly()) { continue; } returnvalue = provider.createUser(username, password, name, email); if (returnvalue != null) { break; } } if (returnvalue == null) { throw new UnsupportedOperationException(); } return returnvalue; } public void deleteUser(String username) { boolean isDeleted = false; for (UserProvider provider : userproviders) { if (provider.isReadOnly()) { continue; } provider.deleteUser(username); isDeleted = true; } // all providers are read-only if (!isDeleted) { throw new UnsupportedOperationException(); } } public Collection<User> findUsers(Set<String> fields, String query) throws UnsupportedOperationException { List<User> userList = new ArrayList<User>(); boolean isUnsupported = false; 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 { userList.addAll(provider.findUsers(fields, query)); } 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 Collection<User> findUsers(Set<String> fields, String query, int startIndex, int numResults) throws UnsupportedOperationException { List<User> userList = new ArrayList<User>(); boolean isUnsupported = false; int totalMatchedUserCount = 0; 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 { Set<String> returnvalue = new HashSet<String>(); for (UserProvider provider : userproviders) { returnvalue.addAll(provider.getSearchFields()); } // no search fields were returned if (returnvalue.size() == 0) { throw new UnsupportedOperationException(); } return returnvalue; } public int getUserCount() { int count = 0; for (UserProvider provider : userproviders) { count += provider.getUserCount(); } return count; } public Collection<String> getUsernames() { List<String> returnvalue = new ArrayList<String>(); for (UserProvider provider : userproviders){ returnvalue.addAll(provider.getUsernames()); } return returnvalue; } public Collection<User> getUsers() { List<User> returnvalue = new ArrayList<User>(); for (UserProvider provider : userproviders){ returnvalue.addAll(provider.getUsers()); } return returnvalue; } public Collection<User> getUsers(int startIndex, int numResults) { List<User> userList = new ArrayList<User>(); int totalUserCount = 0; for (UserProvider provider : userproviders) { int providerStartIndex = Math.max((startIndex - totalUserCount), 0); totalUserCount += provider.getUserCount(); if (startIndex >= totalUserCount) { continue; } int providerResultMax = numResults - userList.size(); userList.addAll(provider.getUsers(providerStartIndex, providerResultMax)); if (userList.size() >= numResults) { break; } } return userList; } public boolean isReadOnly() { return false; } public boolean isNameRequired() { return false; } public boolean isEmailRequired() { return false; } public User loadUser(String username) throws UserNotFoundException { for (UserProvider provider : userproviders) { try { return provider.loadUser(username); } catch (UserNotFoundException unfe) { if (Log.isDebugEnabled()) { Log.debug("User " + username + " not found by UserProvider " + provider.getClass().getName()); } } } //if we get this far, no provider was able to load the user throw new UserNotFoundException(); } public void setCreationDate(String username, Date creationDate) throws 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 { 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 { boolean isUnsupported = false; for (UserProvider provider : userproviders) { try { provider.setModificationDate(username, modificationDate); return; } catch (UnsupportedOperationException uoe) { Log.warn("UserProvider.setModificationDate 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 setName(String username, String name) throws UserNotFoundException { boolean isUnsupported = false; for (UserProvider provider : userproviders) { try { provider.setName(username, name); return; } catch (UnsupportedOperationException uoe) { Log.warn("UserProvider.setName 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(); } } }