1 11 12 package org.jivesoftware.messenger.roster; 13 14 import org.jivesoftware.messenger.auth.UnauthorizedException; 15 import org.jivesoftware.messenger.user.UserNotFoundException; 16 import org.jivesoftware.messenger.user.UserAlreadyExistsException; 17 import org.jivesoftware.messenger.user.User; 18 import org.jivesoftware.messenger.user.UserManager; 19 import org.jivesoftware.messenger.*; 20 import org.jivesoftware.messenger.group.GroupManager; 21 import org.jivesoftware.messenger.group.Group; 22 import org.jivesoftware.util.Cacheable; 23 import org.jivesoftware.util.CacheSizes; 24 import org.jivesoftware.util.Log; 25 import org.jivesoftware.util.JiveConstants; 26 import org.jivesoftware.database.JiveID; 27 import org.xmpp.packet.*; 28 29 import java.util.*; 30 import java.util.concurrent.ConcurrentHashMap ; 31 32 43 @JiveID(JiveConstants.ROSTER) 44 public class Roster implements Cacheable { 45 46 49 protected ConcurrentHashMap <String , RosterItem> rosterItems = new ConcurrentHashMap <String , RosterItem>(); 50 51 private RosterItemProvider rosterItemProvider; 52 private String username; 53 private SessionManager sessionManager; 54 private XMPPServer server = XMPPServer.getInstance(); 55 private RoutingTable routingTable; 56 private PresenceManager presenceManager; 57 60 private RosterManager rosterManager; 61 62 63 74 public Roster(String username) { 75 presenceManager = XMPPServer.getInstance().getPresenceManager(); 76 rosterManager = XMPPServer.getInstance().getRosterManager(); 77 sessionManager = SessionManager.getInstance(); 78 this.username = username; 79 80 Collection<Group> sharedGroups = null; 82 Collection<Group> userGroups = null; 83 try { 84 User rosterUser = UserManager.getInstance().getUser(getUsername()); 85 sharedGroups = rosterManager.getSharedGroups(rosterUser); 86 userGroups = GroupManager.getInstance().getGroups(rosterUser); 87 } 88 catch (UserNotFoundException e) { 89 sharedGroups = new ArrayList<Group>(); 90 } 91 92 rosterItemProvider = RosterItemProvider.getInstance(); 94 Iterator items = rosterItemProvider.getItems(username); 95 while (items.hasNext()) { 96 RosterItem item = (RosterItem)items.next(); 97 for (Group group : sharedGroups) { 100 if (group.isUser(item.getJid().getNode())) { 101 item.addSharedGroup(group); 103 } 104 } 105 rosterItems.put(item.getJid().toBareJID(), item); 106 } 107 Map <JID,List<Group>> sharedUsers = getSharedUsers(sharedGroups); 109 for (JID jid : sharedUsers.keySet()) { 110 try { 111 Collection<Group> itemGroups = new ArrayList<Group>(); 112 User user = UserManager.getInstance().getUser(jid.getNode()); 113 String nickname = "".equals(user.getName()) ? jid.getNode() : user.getName(); 114 RosterItem item = new RosterItem(jid, RosterItem.SUB_TO, RosterItem.ASK_NONE, 115 RosterItem.RECV_NONE, nickname , null); 116 for (Group group : sharedUsers.get(jid)) { 118 if (group.isUser(jid.getNode())) { 119 item.addSharedGroup(group); 120 itemGroups.add(group); 121 } 122 else { 123 item.addInvisibleSharedGroup(group); 124 } 125 } 126 if (rosterManager.hasMutualVisibility(username, userGroups, jid.getNode(), 129 itemGroups)) { 130 item.setSubStatus(RosterItem.SUB_BOTH); 131 } 132 else { 133 boolean belongsToGroup = false; 136 for (Group group : sharedUsers.get(jid)) { 137 if (group.isUser(jid.getNode())) { 138 belongsToGroup = true; 139 } 140 } 141 if (!belongsToGroup) { 142 item.setSubStatus(RosterItem.SUB_FROM); 143 } 144 } 145 rosterItems.put(item.getJid().toBareJID(), item); 146 } 147 catch (UserNotFoundException e) { 148 Log.error("Groups (" + sharedUsers.get(jid) + ") include non-existent username (" + 149 jid.getNode() + 150 ")"); 151 } 152 } 153 } 154 155 161 public boolean isRosterItem(JID user) { 162 return rosterItems.containsKey(user.toBareJID()); 163 } 164 165 170 public Collection<RosterItem> getRosterItems() { 171 return Collections.unmodifiableCollection(rosterItems.values()); 172 } 173 174 179 public int getTotalRosterItemCount() { 180 return rosterItems.size(); 181 } 182 183 191 public RosterItem getRosterItem(JID user) throws UserNotFoundException { 192 RosterItem item = rosterItems.get(user.toBareJID()); 193 if (item == null) { 194 throw new UserNotFoundException(user.toBareJID()); 195 } 196 return item; 197 } 198 199 205 public RosterItem createRosterItem(JID user) throws UserAlreadyExistsException, 206 SharedGroupException { 207 return createRosterItem(user, null, null); 208 } 209 210 218 public RosterItem createRosterItem(JID user, String nickname, List<String > groups) 219 throws UserAlreadyExistsException, SharedGroupException { 220 RosterItem item = provideRosterItem(user, nickname, groups); 221 rosterItems.put(item.getJid().toBareJID(), item); 222 return item; 223 } 224 225 232 public void createRosterItem(org.xmpp.packet.Roster.Item item) 233 throws UserAlreadyExistsException, SharedGroupException { 234 RosterItem rosterItem = provideRosterItem(item); 235 rosterItems.put(item.getJID().toBareJID(), rosterItem); 236 } 237 238 244 protected RosterItem provideRosterItem(org.xmpp.packet.Roster.Item item) 245 throws UserAlreadyExistsException, SharedGroupException { 246 return provideRosterItem(item.getJID(), item.getName(), 247 new ArrayList<String >(item.getGroups())); 248 } 249 250 258 protected RosterItem provideRosterItem(JID user, String nickname, List<String > groups) 259 throws UserAlreadyExistsException, SharedGroupException { 260 if (groups != null && !groups.isEmpty()) { 261 Collection<Group> sharedGroups = GroupManager.getInstance().getGroups(); 263 for (String group : groups) { 264 for (Group sharedGroup : sharedGroups) { 265 if (group.equals(sharedGroup.getProperties().get("sharedRoster.displayName"))) { 266 throw new SharedGroupException("Cannot add an item to a shared group"); 267 } 268 } 269 } 270 } 271 org.xmpp.packet.Roster roster = new org.xmpp.packet.Roster(); 272 roster.setType(IQ.Type.set); 273 org.xmpp.packet.Roster.Item item = roster.addItem(user, nickname, null, 274 org.xmpp.packet.Roster.Subscription.none, groups); 275 276 RosterItem rosterItem = rosterItemProvider.createItem(username, new RosterItem(item)); 277 278 broadcast(roster); 280 281 return rosterItem; 282 } 283 284 290 public void updateRosterItem(RosterItem item) throws UserNotFoundException { 291 if (rosterItems.putIfAbsent(item.getJid().toBareJID(), item) == null) { 292 rosterItems.remove(item.getJid().toBareJID()); 293 throw new UserNotFoundException(item.getJid().toBareJID()); 294 } 295 if (item.isShared() && item.getID() == 0) { 297 try { 298 rosterItemProvider.createItem(username, item); 299 } 300 catch (UserAlreadyExistsException e) { 301 } 303 } 304 else { 305 rosterItemProvider.updateItem(username, item); 307 } 308 broadcast(item, true); 311 315 } 316 317 325 public RosterItem deleteRosterItem(JID user, boolean doChecking) throws SharedGroupException { 326 RosterItem itemToRemove = rosterItems.get(user.toBareJID()); 328 if (doChecking && itemToRemove != null && itemToRemove.isShared()) { 329 throw new SharedGroupException("Cannot remove contact that belongs to a shared group"); 330 } 331 332 RosterItem.SubType subType = itemToRemove.getSubStatus(); 333 if (subType == RosterItem.SUB_TO || subType == RosterItem.SUB_BOTH) { 335 Presence presence = new Presence(); 336 presence.setFrom(server.createJID(username, null)); 337 presence.setTo(itemToRemove.getJid()); 338 presence.setType(Presence.Type.unsubscribe); 339 server.getPacketRouter().route(presence); 340 } 341 if (subType == RosterItem.SUB_FROM || subType == RosterItem.SUB_BOTH) { 343 Presence presence = new Presence(); 344 presence.setFrom(server.createJID(username, null)); 345 presence.setTo(itemToRemove.getJid()); 346 presence.setType(Presence.Type.unsubscribed); 347 server.getPacketRouter().route(presence); 348 } 349 RosterItem item = rosterItems.remove(user.toBareJID()); 351 if (item != null) { 352 if (item.getID() > 0) { 355 rosterItemProvider.deleteItem(username, item.getID()); 357 } 358 359 org.xmpp.packet.Roster roster = new org.xmpp.packet.Roster(); 361 roster.setType(IQ.Type.set); 362 roster.addItem(user, org.xmpp.packet.Roster.Subscription.remove); 363 broadcast(roster); 364 } 365 return item; 366 367 } 368 369 374 public String getUsername() { 375 return username; 376 } 377 378 383 public org.xmpp.packet.Roster getReset() { 384 org.xmpp.packet.Roster roster = new org.xmpp.packet.Roster(); 385 386 for (RosterItem item : rosterItems.values()) { 388 if (item.isOnlyShared() && item.getSubStatus() == RosterItem.SUB_FROM) { 390 continue; 391 } 392 org.xmpp.packet.Roster.Ask ask = getAskStatus(item.getAskStatus()); 393 org.xmpp.packet.Roster.Subscription sub = org.xmpp.packet.Roster.Subscription.valueOf(item.getSubStatus() 394 .getName()); 395 List<String > groups = new ArrayList<String >(item.getGroups()); 397 if (groups.contains(null)) { 398 Log.warn("A group is null in roster item: " + item.getJid() + " of user: " + 399 getUsername()); 400 } 401 for (Group sharedGroup : item.getSharedGroups()) { 402 String displayName = sharedGroup.getProperties().get("sharedRoster.displayName"); 403 if (displayName != null) { 404 groups.add(displayName); 405 } 406 else { 407 Log.warn("Found shared group: " + sharedGroup.getName() + 409 " with no displayName"); 410 } 411 } 412 roster.addItem(item.getJid(), item.getNickname(), ask, sub, groups); 414 } 416 return roster; 417 } 418 419 private org.xmpp.packet.Roster.Ask getAskStatus(RosterItem.AskType askType) { 420 if (askType == null || "".equals(askType.getName())) { 421 return null; 422 } 423 return org.xmpp.packet.Roster.Ask.valueOf(askType.getName()); 424 } 425 426 433 public void broadcastPresence(Presence packet) { 434 if (routingTable == null) { 435 routingTable = XMPPServer.getInstance().getRoutingTable(); 436 } 437 if (routingTable == null) { 438 return; 439 } 440 for (RosterItem item : rosterItems.values()) { 441 if (item.getSubStatus() == RosterItem.SUB_BOTH 442 || item.getSubStatus() == RosterItem.SUB_FROM) { 443 JID searchNode = new JID(item.getJid().getNode(), item.getJid().getDomain(), null); 444 Iterator sessions = routingTable.getRoutes(searchNode); 445 packet.setTo(item.getJid()); 446 while (sessions.hasNext()) { 447 ChannelHandler session = (ChannelHandler)sessions.next(); 448 try { 449 session.process(packet); 450 } 451 catch (Exception e) { 452 } 455 } 456 } 457 } 458 } 459 460 467 private Map <JID,List<Group>> getSharedUsers(Collection<Group> sharedGroups) { 468 Map <JID,List<Group>> sharedGroupUsers = new HashMap <JID,List<Group>>(); 471 for (Group group : sharedGroups) { 472 Collection<String > users = rosterManager.getSharedUsersForRoster(group, this); 474 for (String user : users) { 476 JID jid = XMPPServer.getInstance().createJID(user, null); 479 if (!isRosterItem(jid) && !getUsername().equals(user)) { 480 List<Group> groups = sharedGroupUsers.get(jid); 481 if (groups == null) { 482 groups = new ArrayList<Group>(); 483 sharedGroupUsers.put(jid, groups); 484 } 485 groups.add(group); 486 } 487 } 488 } 489 return sharedGroupUsers; 490 } 491 492 private void broadcast(org.xmpp.packet.Roster roster) { 493 JID recipient = server.createJID(username, null); 494 roster.setTo(recipient); 495 if (sessionManager == null) { 496 sessionManager = SessionManager.getInstance(); 497 } 498 try { 499 sessionManager.userBroadcast(username, roster); 500 } 501 catch (UnauthorizedException e) { 502 } 504 } 505 506 516 void broadcast(RosterItem item, boolean optimize) { 517 if (optimize && item.isOnlyShared() && item.getSubStatus() == RosterItem.SUB_FROM) { 519 return; 520 } 521 List<String > groups = new ArrayList<String >(item.getGroups()); 523 for (Group sharedGroup : item.getSharedGroups()) { 524 groups.add(sharedGroup.getProperties().get("sharedRoster.displayName")); 525 } 526 527 org.xmpp.packet.Roster roster = new org.xmpp.packet.Roster(); 528 roster.setType(IQ.Type.set); 529 roster.addItem(item.getJid(), item.getNickname(), 530 getAskStatus(item.getAskStatus()), 531 org.xmpp.packet.Roster.Subscription.valueOf(item.getSubStatus().getName()), 532 groups); 533 broadcast(roster); 534 } 535 536 539 private void probePresence(JID probee) { 540 for (ClientSession session : sessionManager.getSessions(username)) { 541 presenceManager.probePresence(session.getAddress(), probee); 542 } 543 } 544 545 public int getCachedSize() { 546 int size = 0; 549 size += CacheSizes.sizeOfObject(); size += CacheSizes.sizeOfCollection(rosterItems.values()); size += CacheSizes.sizeOfString(username); return size; 553 } 554 555 566 void addSharedUser(Group group, String addedUser) { 567 boolean newItem = false; 568 RosterItem item = null; 569 JID jid = XMPPServer.getInstance().createJID(addedUser, ""); 570 try { 571 item = getRosterItem(jid); 573 if (item.getSharedGroups().contains(group)) { 575 return; 576 } 577 newItem = false; 578 } 579 catch (UserNotFoundException e) { 580 try { 581 User user = UserManager.getInstance().getUser(addedUser); 583 String nickname = "".equals(user.getName()) ? jid.getNode() : user.getName(); 584 item = 585 new RosterItem(jid, RosterItem.SUB_BOTH, RosterItem.ASK_NONE, 586 RosterItem.RECV_NONE, nickname, null); 587 rosterItems.put(item.getJid().toBareJID(), item); 589 newItem = true; 590 } 591 catch (UserNotFoundException ex) { 592 Log.error("Group (" + group.getName() + ") includes non-existent username (" + 593 addedUser + 594 ")"); 595 } 596 } 597 if (newItem || item.isOnlyShared()) { 599 Collection<Group> userGroups = null; 600 Collection<Group> sharedGroups = new ArrayList<Group>(); 601 try { 602 User rosterUser = UserManager.getInstance().getUser(getUsername()); 603 GroupManager groupManager = GroupManager.getInstance(); 604 userGroups = groupManager.getGroups(rosterUser); 605 sharedGroups.addAll(item.getSharedGroups()); 606 sharedGroups.add(group); 608 if (rosterManager.hasMutualVisibility(getUsername(), userGroups, jid.getNode(), 611 sharedGroups)) { 612 item.setSubStatus(RosterItem.SUB_BOTH); 613 } 614 else if (group.isUser(addedUser) && !group.isUser(getUsername())) { 617 item.setSubStatus(RosterItem.SUB_TO); 618 } 619 else if (!group.isUser(addedUser) && group.isUser(getUsername())) { 620 item.setSubStatus(RosterItem.SUB_FROM); 621 } 622 } 623 catch (UserNotFoundException e) { 624 } 625 } 626 627 if (item.getSubStatus() != RosterItem.SUB_FROM) { 629 item.addSharedGroup(group); 630 } 631 else { 632 item.addInvisibleSharedGroup(group); 633 } 634 broadcast(item, true); 636 if (item.getSubStatus() == RosterItem.SUB_BOTH || item.getSubStatus() == RosterItem.SUB_TO) { 638 probePresence(item.getJid()); 639 } 640 } 641 642 650 void addSharedUser(String addedUser, Collection<Group> groups, Group addedGroup) { 651 boolean newItem = false; 652 RosterItem item = null; 653 JID jid = XMPPServer.getInstance().createJID(addedUser, ""); 654 try { 655 item = getRosterItem(jid); 657 newItem = false; 658 } 659 catch (UserNotFoundException e) { 660 try { 661 User user = UserManager.getInstance().getUser(addedUser); 663 String nickname = "".equals(user.getName()) ? jid.getNode() : user.getName(); 664 item = 665 new RosterItem(jid, RosterItem.SUB_BOTH, RosterItem.ASK_NONE, 666 RosterItem.RECV_NONE, nickname, null); 667 rosterItems.put(item.getJid().toBareJID(), item); 669 newItem = true; 670 } 671 catch (UserNotFoundException ex) { 672 Log.error("Couldn't find a user with username (" + addedUser + ")"); 673 } 674 } 675 if (newItem || item.isOnlyShared()) { 677 Collection<Group> userGroups = null; 678 try { 679 User rosterUser = UserManager.getInstance().getUser(getUsername()); 680 GroupManager groupManager = GroupManager.getInstance(); 681 userGroups = groupManager.getGroups(rosterUser); 682 if (rosterManager.hasMutualVisibility(getUsername(), userGroups, jid.getNode(), 685 groups)) { 686 item.setSubStatus(RosterItem.SUB_BOTH); 687 for (Group group : groups) { 688 if (rosterManager.isGroupVisible(group, getUsername())) { 689 item.addSharedGroup(group); 691 } 692 } 693 for (Group group : userGroups) { 698 if (!group.isUser(addedUser) && 699 rosterManager.isGroupVisible(group, addedUser)) { 700 item.addInvisibleSharedGroup(group); 702 } 703 } 704 } 705 else { 706 item.setSubStatus(RosterItem.SUB_FROM); 709 for (Group group : groups) { 711 if (rosterManager.isGroupVisible(group, getUsername())) { 712 item.addSharedGroup(group); 714 item.setSubStatus(RosterItem.SUB_TO); 715 } 716 } 717 if (item.getSubStatus() == RosterItem.SUB_FROM) { 718 item.addInvisibleSharedGroup(addedGroup); 719 } 720 } 721 } 722 catch (UserNotFoundException e) { 723 } 724 } 725 broadcast(item, true); 727 if (item.getSubStatus() == RosterItem.SUB_BOTH || item.getSubStatus() == RosterItem.SUB_TO) { 729 probePresence(item.getJid()); 730 } 731 } 732 733 743 void deleteSharedUser(Group sharedGroup, String deletedUser) { 744 JID jid = XMPPServer.getInstance().createJID(deletedUser, ""); 745 try { 746 RosterItem item = getRosterItem(jid); 748 int groupSize = item.getSharedGroups().size() + item.getInvisibleSharedGroups().size(); 749 if (item.isOnlyShared() && groupSize == 1) { 750 if (!item.getSharedGroups().contains(sharedGroup)) { 752 return; 753 } 754 deleteRosterItem(jid, false); 757 } 758 else { 759 item.removeSharedGroup(sharedGroup); 761 if (item.isOnlyShared()) { 763 Collection<Group> userGroups = null; 764 Collection<Group> sharedGroups = new ArrayList<Group>(); 765 try { 766 User rosterUser = UserManager.getInstance().getUser(getUsername()); 767 GroupManager groupManager = GroupManager.getInstance(); 768 userGroups = groupManager.getGroups(rosterUser); 769 sharedGroups.addAll(item.getSharedGroups()); 770 if (rosterManager.hasMutualVisibility(getUsername(), userGroups, 773 jid.getNode(), sharedGroups)) { 774 item.setSubStatus(RosterItem.SUB_BOTH); 775 } 776 else if (item.getSharedGroups().isEmpty() && 777 !item.getInvisibleSharedGroups().isEmpty()) { 778 item.setSubStatus(RosterItem.SUB_FROM); 779 } 780 else { 781 item.setSubStatus(RosterItem.SUB_TO); 782 } 783 784 } 785 catch (UserNotFoundException e) { 786 } 787 } 788 broadcast(item, false); 790 } 791 } 792 catch (SharedGroupException e) { 793 } 795 catch (UserNotFoundException e) { 796 } 798 } 799 800 void deleteSharedUser(String deletedUser, Collection<Group> groups, Group deletedGroup) { 801 JID jid = XMPPServer.getInstance().createJID(deletedUser, ""); 802 try { 803 RosterItem item = getRosterItem(jid); 805 int groupSize = item.getSharedGroups().size() + item.getInvisibleSharedGroups().size(); 806 if (item.isOnlyShared() && groupSize == 1 && 807 !(deletedGroup.isUser(deletedUser) && 810 rosterManager.isGroupPublic(deletedGroup))) { 811 deleteRosterItem(jid, false); 814 } 815 else { 816 if (!(deletedGroup.isUser(deletedUser) && 819 rosterManager.isGroupPublic(deletedGroup))) { 820 item.removeSharedGroup(deletedGroup); 821 } 822 for (Group group : groups) { 824 if (!rosterManager.isGroupVisible(group, getUsername())) { 825 item.removeSharedGroup(group); 827 } 828 } 829 830 if (item.isOnlyShared()) { 832 Collection<Group> userGroups = null; 833 try { 834 User rosterUser = UserManager.getInstance().getUser(getUsername()); 835 GroupManager groupManager = GroupManager.getInstance(); 836 userGroups = groupManager.getGroups(rosterUser); 837 if (rosterManager.hasMutualVisibility(getUsername(), userGroups, 840 jid.getNode(), groups)) { 841 item.setSubStatus(RosterItem.SUB_BOTH); 842 } 843 else { 844 item.setSubStatus(RosterItem.SUB_FROM); 847 for (Group group : groups) { 849 if (rosterManager.isGroupVisible(group, getUsername())) { 850 item.setSubStatus(RosterItem.SUB_TO); 851 } 852 } 853 } 854 } 855 catch (UserNotFoundException e) { 856 } 857 } 858 broadcast(item, false); 860 } 861 } 862 catch (SharedGroupException e) { 863 } 865 catch (UserNotFoundException e) { 866 } 868 } 869 870 876 void shareGroupRenamed(Collection<String > users) { 877 for (String user : users) { 878 if (username.equals(user)) { 879 continue; 880 } 881 RosterItem item = null; 882 JID jid = XMPPServer.getInstance().createJID(user, ""); 883 try { 884 item = getRosterItem(jid); 886 broadcast(item, true); 888 } 889 catch (UserNotFoundException e) { 890 } 892 } 893 } 894 } | Popular Tags |