public List<Presence> addVisitor(@Nonnull final JID targetUserAddress, @Nonnull final Affiliation actorAffiliation, @Nullable final Role actorRole) throws ForbiddenException, NotAllowedException
    {
        if (Affiliation.admin != actorAffiliation && Affiliation.owner != actorAffiliation && Role.moderator != actorRole) {
            throw new ForbiddenException();
        }

        // A moderator SHOULD NOT be allowed to revoke moderation privileges from someone with a higher affiliation than
        // themselves (i.e., an unaffiliated moderator SHOULD NOT be allowed to revoke moderation privileges from an
        // admin or an owner, and an admin SHOULD NOT be allowed to revoke moderation privileges from an owner).
        final Affiliation targetAffiliation = getAffiliation(targetUserAddress);
        if (targetAffiliation.getValue() < actorAffiliation.getValue()) { // note that Openfire's values are ordered the other way around.
            throw new NotAllowedException();
        }

        return applyRoleChange(targetUserAddress, Role.visitor);
    }
Changes the role of the user within the room to visitor. A visitor can receive messages but
is not allowed to send messages to the room (i.e. does not have voice) and may invite others
to the room.

@param targetUserAddress the (real) JID of the occupant to change to visitor
@param actorAffiliation The room affiliation of the user that is changing the role to visitor.
@param actorRole The room role of the user that is changing the role to visitor (can be null when the user is currently not an occupant).
@return the list of updated presences of all the client resources that the occupant has used to join the room.
@throws ForbiddenException if the actor is allowed to change the role.
xmppserver/src/main/java/org/jivesoftware/openfire/muc/MUCRoom.java