void addSharedUser(JID addedUser, Collection<Group> groups, Group addedGroup) {
        boolean newItem;
        RosterItem item;
        try {
            // Get the RosterItem for the *local* user to add
            item = getRosterItem(addedUser);
            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("Couldn't find a user with username (" + addedUser + ")");
                return;
            }
        }
        // Update the subscription of the item **based on the item groups**
        Collection<Group> userGroups = GroupManager.getInstance().getGroups(getUserJID());
        // 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
        final RosterManager rosterManager = XMPPServer.getInstance().getRosterManager();
        if (rosterManager.hasMutualVisibility(getUsername(), userGroups, addedUser, groups)) {
            item.setSubStatus(RosterItem.SUB_BOTH);
            for (Group group : groups) {
                if (rosterManager.isGroupVisible(group, getUserJID())) {
                    // Add the shared group to the list of shared groups
                    item.addSharedGroup(group);
                }
            }
            // Add to the item the groups of this user that generated a FROM subscription
            // Note: This FROM subscription is overridden by the BOTH subscription but in
            // fact there is a TO-FROM relation between these two users that ends up in a
            // BOTH subscription
            for (Group group : userGroups) {
                if (!group.isUser(addedUser) && rosterManager.isGroupVisible(group, addedUser)) {
                    // Add the shared group to the list of invisible shared groups
                    item.addInvisibleSharedGroup(group);
                }
            }
        } else {
            // If an item already exists then take note of the old subscription status
            RosterItem.SubType prevSubscription = null;
            if (!newItem) {
                prevSubscription = item.getSubStatus();
            }

            // Assume by default that the contact has subscribed from the presence of
            // this user
            item.setSubStatus(RosterItem.SUB_FROM);
            // Check if the user may see the new contact in a shared group
            for (Group group : groups) {
                if (rosterManager.isGroupVisible(group, getUserJID())) {
                    // Add the shared group to the list of shared groups
                    item.addSharedGroup(group);
                    item.setSubStatus(RosterItem.SUB_TO);
                }
            }
            if (item.getSubStatus() == RosterItem.SUB_FROM) {
                item.addInvisibleSharedGroup(addedGroup);
            }

            // 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
xmppserver/src/main/java/org/jivesoftware/openfire/roster/Roster.java