mucroomimpl.java

来自「基于Jabber协议的即时消息服务器」· Java 代码 · 共 1,693 行 · 第 1/5 页

JAVA
1,693
字号
    public Date getEmptyDate() {
        return this.emptyDate;
    }

    public MUCRole getRole() {
        return role;
    }

    public MUCRole getOccupant(String nickname) throws UserNotFoundException {
        if (nickname == null) {
             throw new UserNotFoundException();
        }
        MUCRole role = occupants.get(nickname.toLowerCase());
        if (role != null) {
            return role;
        }
        throw new UserNotFoundException();
    }

    public List<MUCRole> getOccupantsByBareJID(String jid) throws UserNotFoundException {
        List<MUCRole> roles = occupantsByBareJID.get(jid);
        if (roles != null && !roles.isEmpty()) {
            return Collections.unmodifiableList(roles);
        }
        throw new UserNotFoundException();
    }

    public MUCRole getOccupantByFullJID(JID jid) throws UserNotFoundException {
        MUCRole role = occupantsByFullJID.get(jid);
        if (role != null) {
            return role;
        }
        throw new UserNotFoundException();
    }

    public Collection<MUCRole> getOccupants() {
        return Collections.unmodifiableCollection(occupants.values());
    }

    public int getOccupantsCount() {
        return occupants.size();
    }

    public boolean hasOccupant(String nickname) {
        return occupants.containsKey(nickname.toLowerCase());
    }

    public String getReservedNickname(String bareJID) {
        String answer = members.get(bareJID);
        if (answer == null || answer.trim().length() == 0) {
            return null;
        }
        return answer;
    }

    public MUCRole.Affiliation getAffiliation(String bareJID) {
        if (owners.contains(bareJID)) {
            return MUCRole.Affiliation.owner;
        }
        else if (admins.contains(bareJID)) {
            return MUCRole.Affiliation.admin;
        }
        else if (members.containsKey(bareJID)) {
            return MUCRole.Affiliation.member;
        }
        else if (outcasts.contains(bareJID)) {
            return MUCRole.Affiliation.outcast;
        }
        return MUCRole.Affiliation.none;
    }

    public MUCRole joinRoom(String nickname, String password, HistoryRequest historyRequest,
            MUCUser user, Presence presence) throws UnauthorizedException,
            UserAlreadyExistsException, RoomLockedException, ForbiddenException,
            RegistrationRequiredException, ConflictException, ServiceUnavailableException,
            NotAcceptableException {
        MUCRoleImpl joinRole = null;
        lock.writeLock().lock();
        try {
            // If the room has a limit of max user then check if the limit has been reached
            if (isDestroyed || (getMaxUsers() > 0 && getOccupantsCount() >= getMaxUsers())) {
                throw new ServiceUnavailableException();
            }
            boolean isOwner = owners.contains(user.getAddress().toBareJID());
            // If the room is locked and this user is not an owner raise a RoomLocked exception
            if (isLocked()) {
                if (!isOwner) {
                    throw new RoomLockedException();
                }
            }
            // If the user is already in the room raise a UserAlreadyExists exception
            if (occupants.containsKey(nickname.toLowerCase())) {
                throw new UserAlreadyExistsException();
            }
            // If the room is password protected and the provided password is incorrect raise a
            // Unauthorized exception
            if (isPasswordProtected()) {
                if (password == null || !password.equals(getPassword())) {
                    throw new UnauthorizedException();
                }
            }
            // If another user attempts to join the room with a nickname reserved by the first user
            // raise a ConflictException
            if (members.containsValue(nickname)) {
                if (!nickname.equals(members.get(user.getAddress().toBareJID()))) {
                    throw new ConflictException();
                }
            }
            if (isLoginRestrictedToNickname()) {
                String reservedNickname = members.get(user.getAddress().toBareJID());
                if (reservedNickname != null && !nickname.equals(reservedNickname)) {
                    throw new NotAcceptableException();
                }
            }

            // Set the corresponding role based on the user's affiliation
            MUCRole.Role role;
            MUCRole.Affiliation affiliation;
            if (isOwner) {
                // The user is an owner. Set the role and affiliation accordingly.
                role = MUCRole.Role.moderator;
                affiliation = MUCRole.Affiliation.owner;
            }
            else if (server.getSysadmins().contains(user.getAddress().toBareJID())) {
                // The user is a system administrator of the MUC service. Treat him as an owner 
                // although he won't appear in the list of owners
                role = MUCRole.Role.moderator;
                affiliation = MUCRole.Affiliation.owner;
            }
            else if (admins.contains(user.getAddress().toBareJID())) {
                // The user is an admin. Set the role and affiliation accordingly.
                role = MUCRole.Role.moderator;
                affiliation = MUCRole.Affiliation.admin;
            }
            else if (members.containsKey(user.getAddress().toBareJID())) {
                // The user is a member. Set the role and affiliation accordingly.
                role = MUCRole.Role.participant;
                affiliation = MUCRole.Affiliation.member;
            }
            else if (outcasts.contains(user.getAddress().toBareJID())) {
                // The user is an outcast. Raise a "Forbidden" exception.
                throw new ForbiddenException();
            }
            else {
                // The user has no affiliation (i.e. NONE). Set the role accordingly.
                if (isMembersOnly()) {
                    // The room is members-only and the user is not a member. Raise a
                    // "Registration Required" exception.
                    throw new RegistrationRequiredException();
                }
                role = (isModerated() ? MUCRole.Role.visitor : MUCRole.Role.participant);
                affiliation = MUCRole.Affiliation.none;
            }
            // Create a new role for this user in this room
            joinRole =
                    new MUCRoleImpl(server, this, nickname, role, affiliation, (MUCUserImpl) user,
                            presence, router);
            // Add the new user as an occupant of this room
            occupants.put(nickname.toLowerCase(), joinRole);
            // Update the tables of occupants based on the bare and full JID
            List<MUCRole> list = occupantsByBareJID.get(user.getAddress().toBareJID());
            if (list == null) {
                list = new ArrayList<MUCRole>();
                occupantsByBareJID.put(user.getAddress().toBareJID(), list);
            }
            list.add(joinRole);
            occupantsByFullJID.put(user.getAddress(), joinRole);
        }
        finally {
            lock.writeLock().unlock();
        }
        // Send presence of existing occupants to new occupant
        sendInitialPresences(joinRole);
        // It is assumed that the room is new based on the fact that it's locked and
        // that it was locked when it was created.
        boolean isRoomNew = isLocked() && creationDate.getTime() == lockedTime;
        try {
            // Send the presence of this new occupant to existing occupants
            Presence joinPresence = joinRole.getPresence().createCopy();
            if (isRoomNew) {
                Element frag = joinPresence.getChildElement(
                        "x", "http://jabber.org/protocol/muc#user");
                frag.addElement("status").addAttribute("code", "201");
            }
            broadcastPresence(joinPresence);
        }
        catch (Exception e) {
            Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
        }
        // If the room has just been created send the "room locked until configuration is
        // confirmed" message
        if (isRoomNew) {
            Message message = new Message();
            message.setType(Message.Type.groupchat);
            message.setBody(LocaleUtils.getLocalizedString("muc.new"));
            message.setFrom(role.getRoleAddress());
            joinRole.send(message);
        }
        else if (isLocked()) {
            // Warn the owner that the room is locked but it's not new
            Message message = new Message();
            message.setType(Message.Type.groupchat);
            message.setBody(LocaleUtils.getLocalizedString("muc.locked"));
            message.setFrom(role.getRoleAddress());
            joinRole.send(message);
        }
        else if (canAnyoneDiscoverJID()) {
            // Warn the new occupant that the room is non-anonymous (i.e. his JID will be
            // public)
            Message message = new Message();
            message.setType(Message.Type.groupchat);
            message.setBody(LocaleUtils.getLocalizedString("muc.warnnonanonymous"));
            message.setFrom(role.getRoleAddress());
            Element frag = message.addChildElement("x", "http://jabber.org/protocol/muc#user");
            frag.addElement("status").addAttribute("code", "100");
            joinRole.send(message);
        }
        if (historyRequest == null) {
            Iterator history = roomHistory.getMessageHistory();
            while (history.hasNext()) {
                joinRole.send((Message) history.next());
            }
        }
        else {
            historyRequest.sendHistory(joinRole, roomHistory);
        }
        // Update the date when the last occupant left the room
        setEmptyDate(null);
        return joinRole;
    }

    /**
     * Sends presence of existing occupants to new occupant.
     *
     * @param joinRole the role of the new occupant in the room.
     */
    private void sendInitialPresences(MUCRoleImpl joinRole) {
        for (MUCRole occupant : occupants.values()) {
            if (occupant == joinRole) {
                continue;
            }
            Presence occupantPresence = occupant.getPresence();
            // Skip to the next occupant if we cannot send presence of this occupant
            if (hasToCheckRoleToBroadcastPresence()) {
                Element frag = occupantPresence.getChildElement("x",
                        "http://jabber.org/protocol/muc#user");
                // Check if we can broadcast the presence for this role
                if (!canBroadcastPresence(frag.element("item").attributeValue("role"))) {
                    continue;
                }
            }
            // Don't include the occupant's JID if the room is semi-anon and the new occupant
            // is not a moderator
            if (!canAnyoneDiscoverJID() && MUCRole.Role.moderator != joinRole.getRole()) {
                occupantPresence = occupantPresence.createCopy();
                Element frag = occupantPresence.getChildElement("x",
                        "http://jabber.org/protocol/muc#user");
                frag.element("item").addAttribute("jid", null);
            }
            joinRole.send(occupantPresence);
        }
    }

    public void leaveRoom(String nickname) throws UserNotFoundException {
        MUCRole leaveRole = null;
        lock.writeLock().lock();
        try {
            leaveRole = occupants.remove(nickname.toLowerCase());
            if (leaveRole == null) {
                throw new UserNotFoundException();
            }
            // Removes the role from the room
            removeOccupantRole(leaveRole);

            // TODO Implement this: If the room owner becomes unavailable for any reason before
            // submitting the form (e.g., a lost connection), the service will receive a presence
            // stanza of type "unavailable" from the owner to the room@service/nick or room@service
            // (or both). The service MUST then destroy the room, sending a presence stanza of type
            // "unavailable" from the room to the owner including a <destroy/> element and reason
            // (if provided) as defined under the "Destroying a Room" use case.

            // Remove the room from the server only if there are no more occupants and the room is
            // not persistent
            if (occupants.isEmpty() && !isPersistent()) {
                endTime = System.currentTimeMillis();
                server.removeChatRoom(name);
            }
            if (occupants.isEmpty()) {
                // Update the date when the last occupant left the room
                setEmptyDate(new Date());
            }
        }
        finally {
            lock.writeLock().unlock();
        }

        try {
            Presence presence = leaveRole.getPresence().createCopy();
            presence.setType(Presence.Type.unavailable);
            presence.setStatus(null);
            // Inform the leaving user that he/she has left the room
            leaveRole.send(presence);
            // Inform the rest of the room occupants that the user has left the room
            broadcastPresence(presence);
        }
        catch (Exception e) {
            Log.error(e);
        }
    }

    /**
     * Removes the role of the occupant from all the internal occupants collections. The role will
     * also be removed from the user's roles.
     *
     * @param leaveRole the role to remove.
     */
    private void removeOccupantRole(MUCRole leaveRole) {
        occupants.remove(leaveRole.getNickname().toLowerCase());

        MUCUser user = leaveRole.getChatUser();
        // Notify the user that he/she is no longer in the room
        user.removeRole(getName());
        // Update the tables of occupants based on the bare and full JID
        List list = occupantsByBareJID.get(user.getAddress().toBareJID());
        if (list != null) {
            list.remove(leaveRole);
            if (list.isEmpty()) {
                occupantsByBareJID.remove(user.getAddress().toBareJID());
            }
        }
        occupantsByFullJID.remove(user.getAddress());
    }

    public void destroyRoom(String alternateJID, String reason) {
        MUCRole leaveRole = null;
        Collection<MUCRole> removedRoles = new ArrayList<MUCRole>();
        lock.writeLock().lock();
        try {
            // Remove each occupant

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?