public void addMessage(Message packet) {
        boolean isSubjectChangeRequest = isSubjectChangeRequest(packet);
        JID fromJID = packet.getFrom();
        // Don't keep messages whose sender is the room itself (thus address without resource)
        // unless the message is changing the room's subject
        if (!isSubjectChangeRequest &&
            (fromJID == null || fromJID.toString().isEmpty() ||
             fromJID.equals(getRoom().getSelfRepresentation().getOccupantJID()))) {
            return;
        }
        // Do not store regular messages if there is no message strategy (keep subject change requests)
        if (!isSubjectChangeRequest && !historyStrategy.isHistoryEnabled()) {
            return;
        }

        // Ignore empty messages (no subject AND no body)
        if (!isSubjectChangeRequest &&
            (packet.getBody() == null || packet.getBody().trim().isEmpty())) {
            return;
        }

        Message packetToAdd = packet.createCopy();

        // Check if the room has changed its configuration
        if (isNonAnonymousRoom != getRoom().canAnyoneDiscoverJID()) {
            isNonAnonymousRoom = getRoom().canAnyoneDiscoverJID();
            // Update the "from" attribute of the delay information in the history
            // TODO Make this update in a separate thread
            for (Iterator<Message> it = getMessageHistory(); it.hasNext();) {
                Message message = it.next();
                Element delayElement = message.getChildElement("delay", "urn:xmpp:delay");
                if (getRoom().canAnyoneDiscoverJID()) {
                    // Set the Full JID as the "from" attribute // TODO: This is pretty dodgy, as it depends on the user still being in the room. JIDs _should_ have been stored with the message.
                    try {
                        List<MUCOccupant> occupants = getRoom().getOccupantsByNickname(message.getFrom().getResource());
                        if (!occupants.isEmpty()) {
                            delayElement.addAttribute("from", occupants.get(0).getUserAddress().toString());
                        }
                    }
                    catch (UserNotFoundException e) {
                        // Ignore.
                    }
                }
                else {
                    // Set the Room JID as the "from" attribute
                    delayElement.addAttribute("from", message.getFrom().toString());
                }
            }

        }

        // Add the delay information to the message
        Element delayInformation = packetToAdd.addChildElement("delay", "urn:xmpp:delay");
        Date current = new Date();
        delayInformation.addAttribute("stamp", XMPPDateTimeFormat.format(current));
        if (getRoom().canAnyoneDiscoverJID()) {
            // Set the Full JID as the "from" attribute // TODO: This is pretty dodgy, as it depends on the user still being in the room. JIDs _should_ have been stored with the message.
            try {
                List<MUCOccupant> occupants = getRoom().getOccupantsByNickname(packet.getFrom().getResource());
                if (!occupants.isEmpty()) {
                    delayInformation.addAttribute("from", occupants.get(0).getUserAddress().toString());
                }
            }
            catch (UserNotFoundException e) {
                // Ignore.
            }
        }
        else {
            // Set the Room JID as the "from" attribute
            delayInformation.addAttribute("from", packet.getFrom().toString());
        }
        historyStrategy.addMessage(packetToAdd);
    }
This constructor is provided to comply with the Externalizable interface contract. It should not be used directly.
xmppserver/src/main/java/org/jivesoftware/openfire/muc/MUCRoomHistory.java