Commit 803657b2 authored by Matt Tucker's avatar Matt Tucker Committed by matt

More cache and general cleanup.

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@5250 b35dd754-fafc-0310-a699-88a17e54d16e
parent c4633958
...@@ -67,27 +67,23 @@ public class Group implements Cacheable { ...@@ -67,27 +67,23 @@ public class Group implements Cacheable {
* @return the name of the groups that are shared groups. * @return the name of the groups that are shared groups.
*/ */
static Set<String> getSharedGroupsNames() { static Set<String> getSharedGroupsNames() {
// TODO: add caching
Set<String> groupNames = new HashSet<String>(); Set<String> groupNames = new HashSet<String>();
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
ResultSet rs = null;
try { try {
con = DbConnectionManager.getConnection(); con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_SHARED_GROUPS); pstmt = con.prepareStatement(LOAD_SHARED_GROUPS);
ResultSet rs = pstmt.executeQuery(); rs = pstmt.executeQuery();
while (rs.next()) { while (rs.next()) {
groupNames.add(rs.getString(1)); groupNames.add(rs.getString(1));
} }
rs.close();
} }
catch (SQLException sqle) { catch (SQLException sqle) {
Log.error(sqle); Log.error(sqle);
} }
finally { finally {
try { if (pstmt != null) pstmt.close(); } DbConnectionManager.closeConnection(rs, pstmt, con);
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
} }
return groupNames; return groupNames;
} }
...@@ -519,11 +515,12 @@ public class Group implements Cacheable { ...@@ -519,11 +515,12 @@ public class Group implements Cacheable {
private void loadProperties() { private void loadProperties() {
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
ResultSet rs = null;
try { try {
con = DbConnectionManager.getConnection(); con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_PROPERTIES); pstmt = con.prepareStatement(LOAD_PROPERTIES);
pstmt.setString(1, name); pstmt.setString(1, name);
ResultSet rs = pstmt.executeQuery(); rs = pstmt.executeQuery();
while (rs.next()) { while (rs.next()) {
String key = rs.getString(1); String key = rs.getString(1);
String value = rs.getString(2); String value = rs.getString(2);
...@@ -538,16 +535,12 @@ public class Group implements Cacheable { ...@@ -538,16 +535,12 @@ public class Group implements Cacheable {
Log.warn("There is a group property whose key is null of Group: " + name); Log.warn("There is a group property whose key is null of Group: " + name);
} }
} }
rs.close();
} }
catch (SQLException sqle) { catch (SQLException sqle) {
Log.error(sqle); Log.error(sqle);
} }
finally { finally {
try { if (pstmt != null) pstmt.close(); } DbConnectionManager.closeConnection(rs, pstmt, con);
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
} }
} }
...@@ -566,10 +559,7 @@ public class Group implements Cacheable { ...@@ -566,10 +559,7 @@ public class Group implements Cacheable {
Log.error(e); Log.error(e);
} }
finally { finally {
try { if (pstmt != null) pstmt.close(); } DbConnectionManager.closeConnection(pstmt, con);
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
} }
} }
...@@ -588,10 +578,7 @@ public class Group implements Cacheable { ...@@ -588,10 +578,7 @@ public class Group implements Cacheable {
Log.error(e); Log.error(e);
} }
finally { finally {
try { if (pstmt != null) pstmt.close(); } DbConnectionManager.closeConnection(pstmt, con);
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
} }
} }
...@@ -609,10 +596,7 @@ public class Group implements Cacheable { ...@@ -609,10 +596,7 @@ public class Group implements Cacheable {
Log.error(e); Log.error(e);
} }
finally { finally {
try { if (pstmt != null) pstmt.close(); } DbConnectionManager.closeConnection(pstmt, con);
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
} }
} }
} }
\ No newline at end of file
...@@ -29,11 +29,15 @@ import java.util.*; ...@@ -29,11 +29,15 @@ import java.util.*;
public class GroupManager { public class GroupManager {
Cache<String, Group> groupCache; Cache<String, Group> groupCache;
Cache<String, Collection<Group>> userGroupCache; Cache<String, Object> groupMetaCache;
private GroupProvider provider; private GroupProvider provider;
private static GroupManager instance = new GroupManager(); private static GroupManager instance = new GroupManager();
private static final String GROUP_COUNT_KEY = "GROUP_COUNT";
private static final String SHARED_GROUPS_KEY = "SHARED_GROUPS";
private static final String GROUP_NAMES_KEY = "GROUP_NAMES";
/** /**
* Returns a singleton instance of GroupManager. * Returns a singleton instance of GroupManager.
* *
...@@ -45,12 +49,13 @@ public class GroupManager { ...@@ -45,12 +49,13 @@ public class GroupManager {
private GroupManager() { private GroupManager() {
// Initialize caches. // Initialize caches.
groupCache = CacheManager.initializeCache("Group", "group", 512 * 1024, groupCache = CacheManager.initializeCache("Group", "group", 1024 * 1024,
JiveConstants.MINUTE*30); JiveConstants.MINUTE*15);
// A cache for all groups and groups related to a particular user // A cache for meta-data around groups: count, group names, groups associated with
userGroupCache = CacheManager.initializeCache("User Group Cache", "userGroup", // a particular user
512 * 1024, JiveConstants.MINUTE*3); groupMetaCache = CacheManager.initializeCache("Group Metadata Cache", "groupMeta",
512 * 1024, JiveConstants.MINUTE*10);
// Load a group provider. // Load a group provider.
String className = JiveGlobals.getXMLProperty("provider.group.className", String className = JiveGlobals.getXMLProperty("provider.group.className",
...@@ -66,33 +71,46 @@ public class GroupManager { ...@@ -66,33 +71,46 @@ public class GroupManager {
GroupEventDispatcher.addListener(new GroupEventListener() { GroupEventDispatcher.addListener(new GroupEventListener() {
public void groupCreated(Group group, Map params) { public void groupCreated(Group group, Map params) {
userGroupCache.clear(); groupMetaCache.clear();
} }
public void groupDeleting(Group group, Map params) { public void groupDeleting(Group group, Map params) {
userGroupCache.clear(); groupMetaCache.clear();
} }
public void groupModified(Group group, Map params) { public void groupModified(Group group, Map params) {
/* Ignore */ /* Ignore */
// TODO: expire cache when a property operation on shared groups.
} }
public void memberAdded(Group group, Map params) { public void memberAdded(Group group, Map params) {
userGroupCache.clear(); groupMetaCache.clear();
} }
public void memberRemoved(Group group, Map params) { public void memberRemoved(Group group, Map params) {
userGroupCache.clear(); groupMetaCache.clear();
} }
public void adminAdded(Group group, Map params) { public void adminAdded(Group group, Map params) {
userGroupCache.clear(); groupMetaCache.clear();
} }
public void adminRemoved(Group group, Map params) { public void adminRemoved(Group group, Map params) {
userGroupCache.clear(); groupMetaCache.clear();
} }
}); });
// Pre-load shared groups. This will provide a faster response
// time to the first client that logs in.
// TODO: use a task engine instead of creating a thread directly.
Runnable task = new Runnable() {
public void run() {
getSharedGroups();
}
};
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();
} }
/** /**
...@@ -113,6 +131,7 @@ public class GroupManager { ...@@ -113,6 +131,7 @@ public class GroupManager {
catch (GroupNotFoundException unfe) { catch (GroupNotFoundException unfe) {
// The group doesn't already exist so we can create a new group // The group doesn't already exist so we can create a new group
newGroup = provider.createGroup(name); newGroup = provider.createGroup(name);
// Update caches.
groupCache.put(name, newGroup); groupCache.put(name, newGroup);
// Fire event. // Fire event.
...@@ -159,7 +178,7 @@ public class GroupManager { ...@@ -159,7 +178,7 @@ public class GroupManager {
// Delete the group. // Delete the group.
provider.deleteGroup(group.getName()); provider.deleteGroup(group.getName());
// Expire all relevant caches. // Expire cache.
groupCache.remove(group.getName()); groupCache.remove(group.getName());
} }
...@@ -167,7 +186,7 @@ public class GroupManager { ...@@ -167,7 +186,7 @@ public class GroupManager {
* Deletes a user from all the groups where he/she belongs. The most probable cause * Deletes a user from all the groups where he/she belongs. The most probable cause
* for this request is that the user has been deleted from the system. * for this request is that the user has been deleted from the system.
* *
* TODO: remove this method and use events isntead. * TODO: remove this method and use events instead.
* *
* @param user the deleted user from the system. * @param user the deleted user from the system.
*/ */
...@@ -195,8 +214,17 @@ public class GroupManager { ...@@ -195,8 +214,17 @@ public class GroupManager {
* @return the total number of groups. * @return the total number of groups.
*/ */
public int getGroupCount() { public int getGroupCount() {
// TODO: add caching. Integer count = (Integer)groupMetaCache.get(GROUP_COUNT_KEY);
return provider.getGroupCount(); if (count == null) {
synchronized(GROUP_COUNT_KEY.intern()) {
count = (Integer)groupMetaCache.get(GROUP_COUNT_KEY);
if (count == null) {
count = provider.getGroupCount();
groupMetaCache.put(GROUP_COUNT_KEY, count);
}
}
}
return count;
} }
/** /**
...@@ -205,8 +233,16 @@ public class GroupManager { ...@@ -205,8 +233,16 @@ public class GroupManager {
* @return an unmodifiable Collection of all groups. * @return an unmodifiable Collection of all groups.
*/ */
public Collection<Group> getGroups() { public Collection<Group> getGroups() {
// TODO: add caching. Collection<String> groupNames = (Collection<String>)groupMetaCache.get(GROUP_NAMES_KEY);
Collection<String> groupNames = provider.getGroupNames(); if (groupNames == null) {
synchronized(GROUP_NAMES_KEY.intern()) {
groupNames = (Collection<String>)groupMetaCache.get(GROUP_NAMES_KEY);
if (groupNames == null) {
groupNames = provider.getGroupNames();
groupMetaCache.put(GROUP_NAMES_KEY, groupNames);
}
}
}
return new GroupCollection(groupNames); return new GroupCollection(groupNames);
} }
...@@ -216,7 +252,16 @@ public class GroupManager { ...@@ -216,7 +252,16 @@ public class GroupManager {
* @return an unmodifiable Collection of all shared groups. * @return an unmodifiable Collection of all shared groups.
*/ */
public Collection<Group> getSharedGroups() { public Collection<Group> getSharedGroups() {
Collection<String> groupNames = Group.getSharedGroupsNames(); Collection<String> groupNames = (Collection<String>)groupMetaCache.get(SHARED_GROUPS_KEY);
if (groupNames == null) {
synchronized(SHARED_GROUPS_KEY.intern()) {
groupNames = (Collection<String>)groupMetaCache.get(SHARED_GROUPS_KEY);
if (groupNames == null) {
groupNames = Group.getSharedGroupsNames();
groupMetaCache.put(SHARED_GROUPS_KEY, groupNames);
}
}
}
return new GroupCollection(groupNames); return new GroupCollection(groupNames);
} }
...@@ -232,8 +277,18 @@ public class GroupManager { ...@@ -232,8 +277,18 @@ public class GroupManager {
* @return an Iterator for all groups in the specified range. * @return an Iterator for all groups in the specified range.
*/ */
public Collection<Group> getGroups(int startIndex, int numResults) { public Collection<Group> getGroups(int startIndex, int numResults) {
// TODO: add caching String key = GROUP_NAMES_KEY + startIndex + "," + numResults;
Collection<String> groupNames = provider.getGroupNames(startIndex, numResults);
Collection<String> groupNames = (Collection<String>)groupMetaCache.get(key);
if (groupNames == null) {
synchronized(key.intern()) {
groupNames = (Collection<String>)groupMetaCache.get(key);
if (groupNames == null) {
groupNames = provider.getGroupNames(startIndex, numResults);
groupMetaCache.put(key, groupNames);
}
}
}
return new GroupCollection(groupNames); return new GroupCollection(groupNames);
} }
...@@ -254,8 +309,18 @@ public class GroupManager { ...@@ -254,8 +309,18 @@ public class GroupManager {
* @return all groups that an entity belongs to. * @return all groups that an entity belongs to.
*/ */
public Collection<Group> getGroups(JID user) { public Collection<Group> getGroups(JID user) {
// TODO: add caching String key = user.toBareJID();
Collection<String> groupNames = provider.getGroupNames(user);
Collection<String> groupNames = (Collection<String>)groupMetaCache.get(key);
if (groupNames == null) {
synchronized(key.intern()) {
groupNames = (Collection<String>)groupMetaCache.get(key);
if (groupNames == null) {
groupNames = provider.getGroupNames(user);
groupMetaCache.put(key, groupNames);
}
}
}
return new GroupCollection(groupNames); return new GroupCollection(groupNames);
} }
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
package org.jivesoftware.wildfire.ldap; package org.jivesoftware.wildfire.ldap;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.wildfire.XMPPServer; import org.jivesoftware.wildfire.XMPPServer;
...@@ -44,8 +43,6 @@ public class LdapGroupProvider implements GroupProvider { ...@@ -44,8 +43,6 @@ public class LdapGroupProvider implements GroupProvider {
private LdapManager manager; private LdapManager manager;
private UserManager userManager; private UserManager userManager;
private int groupCount;
private long expiresStamp;
private String[] standardAttributes; private String[] standardAttributes;
/** /**
...@@ -54,8 +51,6 @@ public class LdapGroupProvider implements GroupProvider { ...@@ -54,8 +51,6 @@ public class LdapGroupProvider implements GroupProvider {
public LdapGroupProvider() { public LdapGroupProvider() {
manager = LdapManager.getInstance(); manager = LdapManager.getInstance();
userManager = UserManager.getInstance(); userManager = UserManager.getInstance();
groupCount = -1;
expiresStamp = System.currentTimeMillis();
standardAttributes = new String[3]; standardAttributes = new String[3];
standardAttributes[0] = manager.getGroupNameField(); standardAttributes[0] = manager.getGroupNameField();
standardAttributes[1] = manager.getGroupDescriptionField(); standardAttributes[1] = manager.getGroupDescriptionField();
...@@ -154,10 +149,6 @@ public class LdapGroupProvider implements GroupProvider { ...@@ -154,10 +149,6 @@ public class LdapGroupProvider implements GroupProvider {
} }
public int getGroupCount() { public int getGroupCount() {
// Cache group count for 5 minutes.
if (groupCount != -1 && System.currentTimeMillis() < expiresStamp) {
return groupCount;
}
if (manager.isDebugEnabled()) { if (manager.isDebugEnabled()) {
Log.debug("Trying to get the number of groups in the system."); Log.debug("Trying to get the number of groups in the system.");
} }
...@@ -182,9 +173,6 @@ public class LdapGroupProvider implements GroupProvider { ...@@ -182,9 +173,6 @@ public class LdapGroupProvider implements GroupProvider {
answer.next(); answer.next();
count++; count++;
} }
// Cache the group count.
this.groupCount = count;
this.expiresStamp = System.currentTimeMillis() + JiveConstants.MINUTE * 5;
} }
catch (Exception e) { catch (Exception e) {
Log.error(e); Log.error(e);
...@@ -562,7 +550,7 @@ public class LdapGroupProvider implements GroupProvider { ...@@ -562,7 +550,7 @@ public class LdapGroupProvider implements GroupProvider {
ctx = manager.getContext(); ctx = manager.getContext();
SearchControls searchControls = new SearchControls(); SearchControls searchControls = new SearchControls();
searchControls.setReturningAttributes(new String[]{manager.getUsernameField()}); searchControls.setReturningAttributes(new String[] { manager.getUsernameField() });
// See if recursive searching is enabled. Otherwise, only search one level. // See if recursive searching is enabled. Otherwise, only search one level.
if (manager.isSubTreeSearch()) { if (manager.isSubTreeSearch()) {
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
...@@ -571,7 +559,6 @@ public class LdapGroupProvider implements GroupProvider { ...@@ -571,7 +559,6 @@ public class LdapGroupProvider implements GroupProvider {
searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE); searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
} }
String userSearchFilter = MessageFormat.format(manager.getSearchFilter(), "*");
XMPPServer server = XMPPServer.getInstance(); XMPPServer server = XMPPServer.getInstance();
String serverName = server.getServerInfo().getName(); String serverName = server.getServerInfo().getName();
// Build 3 groups. // Build 3 groups.
...@@ -594,44 +581,42 @@ public class LdapGroupProvider implements GroupProvider { ...@@ -594,44 +581,42 @@ public class LdapGroupProvider implements GroupProvider {
catch (Exception e) { catch (Exception e) {
description = ""; description = "";
} }
TreeSet<JID> members = new TreeSet<JID>(); Set<JID> members = new TreeSet<JID>();
Attribute member = a.get(manager.getGroupMemberField()); Attribute memberField = a.get(manager.getGroupMemberField());
NamingEnumeration ne = member.getAll(); if (memberField != null) {
NamingEnumeration ne = memberField.getAll();
while (ne.hasMore()) { while (ne.hasMore()) {
String username = (String) ne.next(); String username = (String) ne.next();
if (!manager.isPosixMode()) { //userName is full dn if not posix // If not posix mode, each group member is stored as a full DN.
if (!manager.isPosixMode()) {
try { try {
// LdapName will not generate spaces around an '=' // Try to find the username with a regex pattern match.
// (according to the docs)
Matcher matcher = pattern.matcher(username); Matcher matcher = pattern.matcher(username);
if (matcher.matches() && matcher.groupCount() == 3) { if (matcher.matches() && matcher.groupCount() == 3) {
// The username is in the DN, no additional search needed // The username is in the DN, no additional search needed
username = matcher.group(2); username = matcher.group(2);
} }
// The regex pattern match failed. This will happen if the
// the member DN's don't use the standard username field. For
// example, Active Directory has a username field of
// sAMAccountName, but stores group members as "CN=...".
else { else {
// We have to do a new search to find the username field // Create an LDAP name with the full DN.
LdapName ldapName = new LdapName(username);
// Get the CN using LDAP // Turn the LDAP name into something we can use in a
LdapName ldapname = new LdapName(username); // search by stripping off the comma.
String ldapcn = ldapname.get(ldapname.size() - 1); String userDNPart = ldapName.get(ldapName.size() - 1);
String combinedFilter = NamingEnumeration usrAnswer = ctx.search("",
"(&(" + ldapcn + ")" + userSearchFilter + ")"; userDNPart, searchControls);
NamingEnumeration usrAnswer =
ctx.search("", combinedFilter, searchControls);
if (usrAnswer.hasMoreElements()) { if (usrAnswer.hasMoreElements()) {
username = (String) ((SearchResult) usrAnswer.next()) username = (String) ((SearchResult) usrAnswer.next())
.getAttributes().get( .getAttributes().get(
manager.getUsernameField()).get(); manager.getUsernameField()).get();
} }
else {
throw new UserNotFoundException();
}
} }
} }
catch (Exception e) { catch (Exception e) {
if (manager.isDebugEnabled()) { Log.error(e);
Log.debug("Error populating user with DN: " + username, e);
}
} }
} }
// A search filter may have been defined in the LdapUserProvider. // A search filter may have been defined in the LdapUserProvider.
...@@ -662,19 +647,25 @@ public class LdapGroupProvider implements GroupProvider { ...@@ -662,19 +647,25 @@ public class LdapGroupProvider implements GroupProvider {
members.add(userJID); members.add(userJID);
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
// We can safely ignore this error. It likely means that
// the user didn't pass the search filter that's defined.
// So, we want to simply ignore the user as a group member.
if (manager.isDebugEnabled()) { if (manager.isDebugEnabled()) {
Log.debug("User not found: " + username); Log.debug("User not found: " + username);
} }
} }
} }
}
if (manager.isDebugEnabled()) { if (manager.isDebugEnabled()) {
Log.debug("Adding group \"" + name + "\" with " + members.size() + Log.debug("Adding group \"" + name + "\" with " + members.size() +
" members."); " members.");
} }
Group g = new Group(name, description, members, new ArrayList<JID>()); Collection<JID> admins = Collections.emptyList();
groups.put(name, g); Group group = new Group(name, description, members, admins);
groups.put(name, group);
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace();
if (manager.isDebugEnabled()) { if (manager.isDebugEnabled()) {
Log.debug("Error while populating group, " + name + ".", e); Log.debug("Error while populating group, " + name + ".", e);
} }
......
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