Commit a9ec7c81 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Optimization work (avoid loading a user when possible). JM-599

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@3579 b35dd754-fafc-0310-a699-88a17e54d16e
parent 3076f778
...@@ -7,6 +7,7 @@ import org.jivesoftware.wildfire.XMPPServer; ...@@ -7,6 +7,7 @@ import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.auth.UnauthorizedException; import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.disco.ServerFeaturesProvider; import org.jivesoftware.wildfire.disco.ServerFeaturesProvider;
import org.jivesoftware.wildfire.roster.RosterItem; import org.jivesoftware.wildfire.roster.RosterItem;
import org.jivesoftware.wildfire.roster.RosterManager;
import org.jivesoftware.wildfire.user.User; import org.jivesoftware.wildfire.user.User;
import org.jivesoftware.wildfire.user.UserManager; import org.jivesoftware.wildfire.user.UserManager;
import org.jivesoftware.wildfire.user.UserNotFoundException; import org.jivesoftware.wildfire.user.UserNotFoundException;
...@@ -28,6 +29,7 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr ...@@ -28,6 +29,7 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr
private IQHandlerInfo info; private IQHandlerInfo info;
private PresenceManager presenceManager; private PresenceManager presenceManager;
private RosterManager rosterManager;
public IQLastActivityHandler() { public IQLastActivityHandler() {
super("XMPP Last Activity Handler"); super("XMPP Last Activity Handler");
...@@ -47,12 +49,12 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr ...@@ -47,12 +49,12 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr
} }
try { try {
User user = UserManager.getInstance().getUser(username); RosterItem item = rosterManager.getRoster(username).getRosterItem(packet.getFrom());
RosterItem item = user.getRoster().getRosterItem(packet.getFrom());
// Check that the user requesting this information is subscribed to the user's presence // Check that the user requesting this information is subscribed to the user's presence
if (item.getSubStatus() == RosterItem.SUB_FROM || if (item.getSubStatus() == RosterItem.SUB_FROM ||
item.getSubStatus() == RosterItem.SUB_BOTH) { item.getSubStatus() == RosterItem.SUB_BOTH) {
if (sessionManager.getSessions(username).isEmpty()) { if (sessionManager.getSessions(username).isEmpty()) {
User user = UserManager.getInstance().getUser(username);
// The user is offline so answer the user's "last available time and the // The user is offline so answer the user's "last available time and the
// status message of the last unavailable presence received from the user" // status message of the last unavailable presence received from the user"
long lastActivityTime = presenceManager.getLastActivity(user); long lastActivityTime = presenceManager.getLastActivity(user);
...@@ -81,8 +83,8 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr ...@@ -81,8 +83,8 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr
return info; return info;
} }
public Iterator getFeatures() { public Iterator<String> getFeatures() {
ArrayList features = new ArrayList(); ArrayList<String> features = new ArrayList<String>();
features.add("jabber:iq:last"); features.add("jabber:iq:last");
return features.iterator(); return features.iterator();
} }
...@@ -90,5 +92,6 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr ...@@ -90,5 +92,6 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr
public void initialize(XMPPServer server) { public void initialize(XMPPServer server) {
super.initialize(server); super.initialize(server);
presenceManager = server.getPresenceManager(); presenceManager = server.getPresenceManager();
rosterManager = server.getRosterManager();
} }
} }
\ No newline at end of file
...@@ -11,9 +11,7 @@ ...@@ -11,9 +11,7 @@
package org.jivesoftware.wildfire.handler; package org.jivesoftware.wildfire.handler;
import org.dom4j.DocumentHelper;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.IQHandlerInfo; import org.jivesoftware.wildfire.IQHandlerInfo;
import org.jivesoftware.wildfire.PacketException; import org.jivesoftware.wildfire.PacketException;
...@@ -62,6 +60,7 @@ import org.xmpp.packet.PacketError; ...@@ -62,6 +60,7 @@ import org.xmpp.packet.PacketError;
public class IQvCardHandler extends IQHandler { public class IQvCardHandler extends IQHandler {
private IQHandlerInfo info; private IQHandlerInfo info;
private XMPPServer server;
private UserManager userManager; private UserManager userManager;
public IQvCardHandler() { public IQvCardHandler() {
...@@ -70,61 +69,60 @@ public class IQvCardHandler extends IQHandler { ...@@ -70,61 +69,60 @@ public class IQvCardHandler extends IQHandler {
} }
public IQ handleIQ(IQ packet) throws UnauthorizedException, PacketException { public IQ handleIQ(IQ packet) throws UnauthorizedException, PacketException {
IQ result = null; IQ result = IQ.createResultIQ(packet);
try {
IQ.Type type = packet.getType(); IQ.Type type = packet.getType();
if (type.equals(IQ.Type.set)) { if (type.equals(IQ.Type.set)) {
result = IQ.createResultIQ(packet); try {
User user = userManager.getUser(packet.getFrom().getNode()); User user = userManager.getUser(packet.getFrom().getNode());
// Proper format
Element vcard = packet.getChildElement(); Element vcard = packet.getChildElement();
if (vcard != null) { if (vcard != null) {
try {
VCardManager.getInstance().setVCard(user.getUsername(), vcard); VCardManager.getInstance().setVCard(user.getUsername(), vcard);
} }
}
catch (UserNotFoundException e) {
result = IQ.createResultIQ(packet);
result.setChildElement(packet.getChildElement().createCopy());
result.setError(PacketError.Condition.item_not_found);
}
catch (Exception e) { catch (Exception e) {
Log.error(e); Log.error(e);
result.setError(PacketError.Condition.internal_server_error); result.setError(PacketError.Condition.internal_server_error);
} }
} }
}
else if (type.equals(IQ.Type.get)) { else if (type.equals(IQ.Type.get)) {
JID recipient = packet.getTo(); JID recipient = packet.getTo();
// If no TO was specified then get the vCard of the sender of the packet // If no TO was specified then get the vCard of the sender of the packet
if (recipient == null) { if (recipient == null) {
recipient = packet.getFrom(); recipient = packet.getFrom();
} }
// By default return an empty vCard
result = IQ.createResultIQ(packet); result.setChildElement("vCard", "vcard-temp");
Element vcard = DocumentHelper.createElement(QName.get("vCard", "vcard-temp"));
result.setChildElement(vcard);
// Only try to get the vCard values of non-anonymous users // Only try to get the vCard values of non-anonymous users
if (recipient != null && userManager.isRegisteredUser(recipient.getNode())) { if (recipient != null) {
User user = userManager.getUser(recipient.getNode()); if (recipient.getNode() != null && server.isLocal(recipient)) {
VCardManager vManager = VCardManager.getInstance(); VCardManager vManager = VCardManager.getInstance();
Element userVCard = vManager.getVCard(user.getUsername()); Element userVCard = vManager.getVCard(recipient.getNode());
if (userVCard != null) { if (userVCard != null) {
result.setChildElement(userVCard); result.setChildElement(userVCard);
} }
} }
}
else { else {
result = IQ.createResultIQ(packet); result = IQ.createResultIQ(packet);
result.setChildElement(packet.getChildElement().createCopy()); result.setChildElement(packet.getChildElement().createCopy());
result.setError(PacketError.Condition.not_acceptable); result.setError(PacketError.Condition.item_not_found);
} }
} }
catch (UserNotFoundException e) { }
result = IQ.createResultIQ(packet); else {
result.setChildElement(packet.getChildElement().createCopy()); result.setChildElement(packet.getChildElement().createCopy());
result.setError(PacketError.Condition.item_not_found); result.setError(PacketError.Condition.not_acceptable);
} }
return result; return result;
} }
public void initialize(XMPPServer server) { public void initialize(XMPPServer server) {
super.initialize(server); super.initialize(server);
this.server = server;
userManager = server.getUserManager(); userManager = server.getUserManager();
} }
......
...@@ -391,7 +391,10 @@ public class LdapGroupProvider implements GroupProvider { ...@@ -391,7 +391,10 @@ public class LdapGroupProvider implements GroupProvider {
// In order to lookup a username from the manager, the username // In order to lookup a username from the manager, the username
// must be a properly escaped JID node. // must be a properly escaped JID node.
String escapedUsername = JID.escapeNode(username); String escapedUsername = JID.escapeNode(username);
if (!escapedUsername.equals(username)) {
// Check if escaped username is valid
userManager.getUser(escapedUsername); userManager.getUser(escapedUsername);
}
// No exception, so the user must exist. Add the user as a group // No exception, so the user must exist. Add the user as a group
// member using the escaped username. // member using the escaped username.
userJID = server.createJID(escapedUsername, null); userJID = server.createJID(escapedUsername, null);
......
...@@ -295,10 +295,19 @@ public class Roster implements Cacheable { ...@@ -295,10 +295,19 @@ public class Roster implements Cacheable {
// If the item only had shared groups before this update then make it persistent // If the item only had shared groups before this update then make it persistent
if (item.isShared() && item.getID() == 0) { if (item.isShared() && item.getID() == 0) {
// Do nothing if item is only shared and it is using the default user name // Do nothing if item is only shared and it is using the default user name
String defaultContactName = UserNameManager.getUserName(item.getJid()); if (item.isOnlyShared()) {
if (item.isOnlyShared() && defaultContactName.equals(item.getNickname())) { String defaultContactName = null;
try {
defaultContactName = UserNameManager.getUserName(item.getJid());
}
catch (UserNotFoundException e) {
// Cannot update a roster item for a local user that does not exist
defaultContactName = item.getNickname();
}
if (defaultContactName.equals(item.getNickname())) {
return; return;
} }
}
try { try {
rosterItemProvider.createItem(username, item); rosterItemProvider.createItem(username, item);
} }
......
...@@ -14,7 +14,6 @@ package org.jivesoftware.wildfire.spi; ...@@ -14,7 +14,6 @@ package org.jivesoftware.wildfire.spi;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper; import org.dom4j.DocumentHelper;
import org.jivesoftware.util.CacheManager;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.*; import org.jivesoftware.wildfire.*;
...@@ -26,6 +25,7 @@ import org.jivesoftware.wildfire.privacy.PrivacyList; ...@@ -26,6 +25,7 @@ import org.jivesoftware.wildfire.privacy.PrivacyList;
import org.jivesoftware.wildfire.privacy.PrivacyListManager; import org.jivesoftware.wildfire.privacy.PrivacyListManager;
import org.jivesoftware.wildfire.roster.Roster; import org.jivesoftware.wildfire.roster.Roster;
import org.jivesoftware.wildfire.roster.RosterItem; import org.jivesoftware.wildfire.roster.RosterItem;
import org.jivesoftware.wildfire.roster.RosterManager;
import org.jivesoftware.wildfire.user.User; import org.jivesoftware.wildfire.user.User;
import org.jivesoftware.wildfire.user.UserManager; import org.jivesoftware.wildfire.user.UserManager;
import org.jivesoftware.wildfire.user.UserNotFoundException; import org.jivesoftware.wildfire.user.UserNotFoundException;
...@@ -51,6 +51,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -51,6 +51,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
private SessionManager sessionManager; private SessionManager sessionManager;
private UserManager userManager; private UserManager userManager;
private RosterManager rosterManager;
private XMPPServer server; private XMPPServer server;
private PacketDeliverer deliverer; private PacketDeliverer deliverer;
private PresenceUpdateHandler presenceUpdateHandler; private PresenceUpdateHandler presenceUpdateHandler;
...@@ -182,19 +183,8 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -182,19 +183,8 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
public void handleProbe(Presence packet) throws UnauthorizedException { public void handleProbe(Presence packet) throws UnauthorizedException {
String username = packet.getTo().getNode(); String username = packet.getTo().getNode();
// Check for a cached roster:
Roster roster = (Roster)CacheManager.getCache("username2roster").get(username);
if (roster == null) {
synchronized(username.intern()) {
roster = (Roster)CacheManager.getCache("username2roster").get(username);
if (roster == null) {
// Not in cache so load a new one:
roster = new Roster(username);
CacheManager.getCache("username2roster").put(username, roster);
}
}
}
try { try {
Roster roster = rosterManager.getRoster(username);
RosterItem item = roster.getRosterItem(packet.getFrom()); RosterItem item = roster.getRosterItem(packet.getFrom());
if (item.getSubStatus() == RosterItem.SUB_FROM if (item.getSubStatus() == RosterItem.SUB_FROM
|| item.getSubStatus() == RosterItem.SUB_BOTH) { || item.getSubStatus() == RosterItem.SUB_BOTH) {
...@@ -225,21 +215,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -225,21 +215,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
public boolean canProbePresence(JID prober, String probee) throws UserNotFoundException { public boolean canProbePresence(JID prober, String probee) throws UserNotFoundException {
// Check that the probee is a valid user RosterItem item = rosterManager.getRoster(probee).getRosterItem(prober);
userManager.getUser(probee);
// Check for a cached roster:
Roster roster = (Roster)CacheManager.getCache("username2roster").get(probee);
if (roster == null) {
synchronized(probee.intern()) {
roster = (Roster)CacheManager.getCache("username2roster").get(probee);
if (roster == null) {
// Not in cache so load a new one:
roster = new Roster(probee);
CacheManager.getCache("username2roster").put(probee, roster);
}
}
}
RosterItem item = roster.getRosterItem(prober);
if (item.getSubStatus() == RosterItem.SUB_FROM if (item.getSubStatus() == RosterItem.SUB_FROM
|| item.getSubStatus() == RosterItem.SUB_BOTH) { || item.getSubStatus() == RosterItem.SUB_BOTH) {
return true; return true;
...@@ -252,16 +228,13 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -252,16 +228,13 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
if (server.isLocal(probee)) { if (server.isLocal(probee)) {
// If the probee is a local user then don't send a probe to the contact's server. // If the probee is a local user then don't send a probe to the contact's server.
// But instead just send the contact's presence to the prober // But instead just send the contact's presence to the prober
if (userManager.isRegisteredUser(probee.getNode())) { Collection<ClientSession> sessions = sessionManager.getSessions(probee.getNode());
Collection<ClientSession> sessions =
sessionManager.getSessions(probee.getNode());
if (sessions.isEmpty()) { if (sessions.isEmpty()) {
// If the probee is not online then try to retrieve his last unavailable // If the probee is not online then try to retrieve his last unavailable
// presence which may contain particular information and send it to the // presence which may contain particular information and send it to the
// prober // prober
try { String presenceXML =
User probeeUser = userManager.getUser(probee.getNode()); userManager.getUserProperty(probee.getNode(), LAST_PRESENCE_PROP);
String presenceXML = probeeUser.getProperties().get(LAST_PRESENCE_PROP);
if (presenceXML != null) { if (presenceXML != null) {
try { try {
// Parse the element // Parse the element
...@@ -282,10 +255,6 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -282,10 +255,6 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
catch (Exception e) { catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e); Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
} }
}
}
catch (UserNotFoundException e) {
} }
} }
else { else {
...@@ -314,7 +283,6 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -314,7 +283,6 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
} }
} }
}
else { else {
Component component = getPresenceComponent(probee); Component component = getPresenceComponent(probee);
if (component != null) { if (component != null) {
...@@ -385,6 +353,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -385,6 +353,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
sessionManager = server.getSessionManager(); sessionManager = server.getSessionManager();
userManager = server.getUserManager(); userManager = server.getUserManager();
presenceUpdateHandler = server.getPresenceUpdateHandler(); presenceUpdateHandler = server.getPresenceUpdateHandler();
rosterManager = server.getRosterManager();
} }
public Component getPresenceComponent(JID probee) { public Component getPresenceComponent(JID probee) {
......
...@@ -11,20 +11,20 @@ ...@@ -11,20 +11,20 @@
package org.jivesoftware.wildfire.user; package org.jivesoftware.wildfire.user;
import org.jivesoftware.wildfire.roster.Roster; import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.XMPPServer; import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.event.UserEventDispatcher; import org.jivesoftware.wildfire.event.UserEventDispatcher;
import org.jivesoftware.util.Log; import org.jivesoftware.wildfire.roster.Roster;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.database.DbConnectionManager;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* Encapsulates information about a user. New users are created using * Encapsulates information about a user. New users are created using
...@@ -40,6 +40,8 @@ public class User implements Cacheable { ...@@ -40,6 +40,8 @@ public class User implements Cacheable {
private static final String LOAD_PROPERTIES = private static final String LOAD_PROPERTIES =
"SELECT name, propValue FROM jiveUserProp WHERE username=?"; "SELECT name, propValue FROM jiveUserProp WHERE username=?";
private static final String LOAD_PROPERTY =
"SELECT propValue FROM jiveUserProp WHERE username=? AND name=?";
private static final String DELETE_PROPERTY = private static final String DELETE_PROPERTY =
"DELETE FROM jiveUserProp WHERE username=? AND name=?"; "DELETE FROM jiveUserProp WHERE username=? AND name=?";
private static final String UPDATE_PROPERTY = private static final String UPDATE_PROPERTY =
...@@ -55,6 +57,41 @@ public class User implements Cacheable { ...@@ -55,6 +57,41 @@ public class User implements Cacheable {
private Map<String,String> properties = null; private Map<String,String> properties = null;
/**
* Returns the value of the specified property for the given username. This method is
* an optimization to avoid loading a user to get a specific property.
*
* @param username the username of the user to get a specific property value.
* @param propertyName the name of the property to return its value.
* @return the value of the specified property for the given username.
*/
public static String getPropertyValue(String username, String propertyName) {
String propertyValue = null;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_PROPERTY);
pstmt.setString(1, username);
pstmt.setString(2, propertyName);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
propertyValue = rs.getString(1);
}
rs.close();
}
catch (SQLException sqle) {
Log.error(sqle);
}
finally {
try { if (pstmt != null) pstmt.close(); }
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
}
return propertyValue;
}
/** /**
* Constructs a new user. All arguments can be <tt>null</tt> except the username. * Constructs a new user. All arguments can be <tt>null</tt> except the username.
* Typically, User objects should not be constructed by end-users of the API. * Typically, User objects should not be constructed by end-users of the API.
......
...@@ -244,6 +244,28 @@ public class UserManager implements IQResultListener { ...@@ -244,6 +244,28 @@ public class UserManager implements IQResultListener {
return provider.findUsers(fields, query); return provider.findUsers(fields, query);
} }
/**
* Returns the value of the specified property for the given username. If the user
* has been loaded into memory then the ask the user to return the value of the
* property. However, if the user is not present in memory then try to get the property
* value directly from the database as a way to optimize the performance.
*
* @param username the username of the user to get a specific property value.
* @param propertyName the name of the property to return its value.
* @return the value of the specified property for the given username.
*/
public String getUserProperty(String username, String propertyName) {
username = username.trim().toLowerCase();
User user = (User) userCache.get(username);
if (user == null) {
return User.getPropertyValue(username, propertyName);
}
else {
// User is in memory so ask the user for the specified property value
return user.getProperties().get(propertyName);
}
}
/** /**
* Returns true if the specified local username belongs to a registered local user. * Returns true if the specified local username belongs to a registered local user.
* *
......
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