void addSharedUser(Group group, JID addedUser) {
        boolean newItem;
        RosterItem item;
        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 +
                        ")");
                return;
            }
        }

        // 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<>();
        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
        final RosterManager rosterManager = XMPPServer.getInstance().getRosterManager();
        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);
        }
    }
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.
xmppserver/src/main/java/org/jivesoftware/openfire/roster/Roster.java