📄 roster.java
字号:
JID from = packet.getFrom();
if (from != null) {
// Try to use the active list of the session. If none was found then try to use
// the default privacy list of the session
ClientSession session = sessionManager.getSession(from);
if (session != null) {
list = session.getActiveList();
list = list == null ? session.getDefaultList() : list;
}
}
if (list == null) {
// No privacy list was found (based on the session) so check if there is a default list
list = PrivacyListManager.getInstance().getDefaultPrivacyList(username);
}
// Broadcast presence to subscribed entities
for (RosterItem item : rosterItems.values()) {
if (item.getSubStatus() == RosterItem.SUB_BOTH || item.getSubStatus() == RosterItem.SUB_FROM) {
packet.setTo(item.getJid());
if (list != null && list.shouldBlockPacket(packet)) {
// Outgoing presence notifications are blocked for this contact
continue;
}
JID searchNode = new JID(item.getJid().getNode(), item.getJid().getDomain(), null, true);
for (JID jid : routingTable.getRoutes(searchNode, null)) {
try {
routingTable.routePacket(jid, packet, false);
}
catch (Exception e) {
// Theoretically only happens if session has been closed.
Log.debug(e);
}
}
}
}
// Broadcast presence to shared contacts whose subscription status is FROM
for (String contact : implicitFrom.keySet()) {
packet.setTo(contact);
if (list != null && list.shouldBlockPacket(packet)) {
// Outgoing presence notifications are blocked for this contact
continue;
}
for (JID jid: routingTable.getRoutes(new JID(contact), null)) {
try {
routingTable.routePacket(jid, packet, false);
}
catch (Exception e) {
// Theoretically only happens if session has been closed.
Log.debug(e);
}
}
}
if (from != null) {
// Broadcast presence to other user's resources
sessionManager.broadcastPresenceToOtherResources(from, packet);
}
}
/**
* Returns the list of users that belong ONLY to a shared group of this user. If the contact
* belongs to the personal roster and a shared group then it wont' be included in the answer.
*
* @param sharedGroups the shared groups of this user.
* @return the list of users that belong ONLY to a shared group of this user.
*/
private Map<JID,List<Group>> getSharedUsers(Collection<Group> sharedGroups) {
// Get the users to process from the shared groups. Users that belong to different groups
// will have one entry in the map associated with all the groups
Map<JID,List<Group>> sharedGroupUsers = new HashMap<JID,List<Group>>();
for (Group group : sharedGroups) {
// Get all the users that should be in this roster
Collection<JID> users = rosterManager.getSharedUsersForRoster(group, this);
// Add the users of the group to the general list of users to process
JID userJID = getUserJID();
for (JID jid : users) {
// Add the user to the answer if the user doesn't belong to the personal roster
// (since we have already added the user to the answer)
boolean isRosterItem = rosterItems.containsKey(jid.toBareJID());
if (!isRosterItem && !userJID.equals(jid)) {
List<Group> groups = sharedGroupUsers.get(jid);
if (groups == null) {
groups = new ArrayList<Group>();
sharedGroupUsers.put(jid, groups);
}
groups.add(group);
}
}
}
return sharedGroupUsers;
}
private void broadcast(org.xmpp.packet.Roster roster) {
JID recipient = server.createJID(username, null, true);
roster.setTo(recipient);
if (sessionManager == null) {
sessionManager = SessionManager.getInstance();
}
sessionManager.userBroadcast(username, roster);
}
/**
* Broadcasts the RosterItem to all the connected resources of this user. Due to performance
* optimizations and due to some clients errors that are showing items with subscription status
* FROM we added a flag that indicates if a roster items that exists only because of a shared
* group with subscription status FROM will not be sent.
*
* @param item the item to broadcast.
* @param optimize true indicates that items that exists only because of a shared
* group with subscription status FROM will not be sent
*/
public void broadcast(RosterItem item, boolean optimize) {
// Do not broadcast items with status FROM that exist only because of shared groups
if (optimize && item.isOnlyShared() && item.getSubStatus() == RosterItem.SUB_FROM) {
return;
}
// Set the groups to broadcast (include personal and shared groups)
List<String> groups = new ArrayList<String>(item.getGroups());
for (Group sharedGroup : item.getSharedGroups()) {
String displayName = sharedGroup.getProperties().get("sharedRoster.displayName");
if (displayName != null) {
groups.add(displayName);
}
}
org.xmpp.packet.Roster roster = new org.xmpp.packet.Roster();
roster.setType(IQ.Type.set);
roster.addItem(item.getJid(), item.getNickname(),
getAskStatus(item.getAskStatus()),
org.xmpp.packet.Roster.Subscription.valueOf(item.getSubStatus().getName()),
groups);
broadcast(roster);
}
/**
* Sends a presence probe to the probee for each connected resource of this user.
*/
private void probePresence(JID probee) {
for (ClientSession session : sessionManager.getSessions(username)) {
presenceManager.probePresence(session.getAddress(), probee);
}
}
public int getCachedSize() {
// Approximate the size of the object in bytes by calculating the size
// of each field.
int size = 0;
size += CacheSizes.sizeOfObject(); // overhead of object
size += CacheSizes.sizeOfCollection(rosterItems.values()); // roster item cache
size += CacheSizes.sizeOfString(username); // username
return size;
}
/**
* Update the roster since a group user has been added to a shared group. Create a new
* RosterItem if the there doesn't exist an item for the added user. The new RosterItem won't be
* saved to the backend store unless the user explicitly subscribes to the contact's presence,
* renames the contact in his roster or adds the item to a personal group. Otherwise the shared
* group will be added to the shared groups lists. In any case an update broadcast will be sent
* to all the users logged resources.
*
* @param group the shared group where the user was added.
* @param addedUser the contact to update in the roster.
*/
void addSharedUser(Group group, JID addedUser) {
boolean newItem = false;
RosterItem item = null;
try {
// Get the RosterItem for the *local* user to add
item = getRosterItem(addedUser);
// Do nothing if the item already includes the shared group
if (item.getSharedGroups().contains(group)) {
return;
}
newItem = false;
}
catch (UserNotFoundException e) {
try {
// Create a new RosterItem for this new user
String nickname = UserNameManager.getUserName(addedUser);
item =
new RosterItem(addedUser, RosterItem.SUB_BOTH, RosterItem.ASK_NONE,
RosterItem.RECV_NONE, nickname, null);
// Add the new item to the list of items
rosterItems.put(item.getJid().toBareJID(), item);
newItem = true;
}
catch (UserNotFoundException ex) {
Log.error("Group (" + group.getName() + ") includes non-existent username (" +
addedUser +
")");
}
}
// If an item already exists then take note of the old subscription status
RosterItem.SubType prevSubscription = null;
if (!newItem) {
prevSubscription = item.getSubStatus();
}
// Update the subscription of the item **based on the item groups**
Collection<Group> userGroups = GroupManager.getInstance().getGroups(getUserJID());
Collection<Group> sharedGroups = new ArrayList<Group>();
sharedGroups.addAll(item.getSharedGroups());
// Add the new group to the list of groups to check
sharedGroups.add(group);
// Set subscription type to BOTH if the roster user belongs to a shared group
// that is mutually visible with a shared group of the new roster item
if (rosterManager.hasMutualVisibility(getUsername(), userGroups, addedUser, sharedGroups)) {
item.setSubStatus(RosterItem.SUB_BOTH);
}
// Update the subscription status depending on the group membership of the new
// user and this user
else if (group.isUser(addedUser) && !group.isUser(getUsername())) {
item.setSubStatus(RosterItem.SUB_TO);
}
else if (!group.isUser(addedUser) && group.isUser(getUsername())) {
item.setSubStatus(RosterItem.SUB_FROM);
}
// Add the shared group to the list of shared groups
if (item.getSubStatus() != RosterItem.SUB_FROM) {
item.addSharedGroup(group);
}
else {
item.addInvisibleSharedGroup(group);
}
// If the item already exists then check if the subscription status should be
// changed to BOTH based on the old and new subscription status
if (prevSubscription != null) {
if (prevSubscription == RosterItem.SUB_TO &&
item.getSubStatus() == RosterItem.SUB_FROM) {
item.setSubStatus(RosterItem.SUB_BOTH);
}
else if (prevSubscription == RosterItem.SUB_FROM &&
item.getSubStatus() == RosterItem.SUB_TO) {
item.setSubStatus(RosterItem.SUB_BOTH);
}
}
// Optimization: Check if we do not need to keep the item in memory
if (item.isOnlyShared() && item.getSubStatus() == RosterItem.SUB_FROM) {
// Remove from memory and do nothing else
rosterItems.remove(item.getJid().toBareJID());
// Cache information about shared contacts with subscription status FROM
implicitFrom.put(item.getJid().toBareJID(), item.getInvisibleSharedGroupsNames());
}
else {
// Remove from list of shared contacts with status FROM (if any)
implicitFrom.remove(item.getJid().toBareJID());
// Ensure that the item is an explicit roster item
rosterItems.put(item.getJid().toBareJID(), item);
// Brodcast to all the user resources of the updated roster item
broadcast(item, true);
// Probe the presence of the new group user
if (item.getSubStatus() == RosterItem.SUB_BOTH ||
item.getSubStatus() == RosterItem.SUB_TO) {
probePresence(item.getJid());
}
}
if (newItem) {
// Fire event indicating that a roster item has been added
RosterEventDispatcher.contactAdded(this, item);
}
else {
// Fire event indicating that a roster item has been updated
RosterEventDispatcher.contactUpdated(this, item);
}
}
/**
* Adds a new contact that belongs to a certain list of groups to the roster. Depending on
* the contact's groups and this user's groups, the presence subscription of the roster item may
* vary.
*
* @param addedUser the new contact to add to the roster
* @param groups the groups where the contact is a member
*/
void addSharedUser(JID addedUser, Collection<Group> groups, Group addedGroup) {
boolean newItem = false;
RosterItem item = null;
try {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -