org.jivesoftware.openfire.muc.HistoryRequest Maven / Gradle / Ivy
/*
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.openfire.muc;
import java.text.ParseException;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import org.dom4j.Element;
import org.jivesoftware.openfire.muc.spi.LocalMUCRole;
import org.jivesoftware.util.XMPPDateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.Message;
/**
* Represents the amount of history requested by an occupant while joining a room. There are
* basically four ways to control the amount of history that a user may receive. Those are: limit
* by the maximum limit of characters to receive, limit by a maximum number of stanzas to receive,
* limit to receive only the messages before a given date or of the last X seconds.
*
* A user may combine any of these four methods. The idea is that the user will receive the smallest
* amount of traffic so the amount of history to collect will stop as soon as any of the requested
* method has reached its limit.
*
* @author Gaston Dombiak
*/
public class HistoryRequest {
private static final Logger Log = LoggerFactory.getLogger(HistoryRequest.class);
private static final XMPPDateTimeFormat xmppDateTime = new XMPPDateTimeFormat();
private int maxChars = -1;
private int maxStanzas = -1;
private int seconds = -1;
private Date since;
public HistoryRequest(Element userFragment) {
Element history = userFragment.element("history");
if (history != null) {
if (history.attribute("maxchars") != null) {
this.maxChars = Integer.parseInt(history.attributeValue("maxchars"));
}
if (history.attribute("maxstanzas") != null) {
this.maxStanzas = Integer.parseInt(history.attributeValue("maxstanzas"));
}
if (history.attribute("seconds") != null) {
this.seconds = Integer.parseInt(history.attributeValue("seconds"));
}
if (history.attribute("since") != null) {
try {
// parse since String into Date
this.since = xmppDateTime.parseString(history.attributeValue("since"));
}
catch(ParseException pe) {
Log.error("Error parsing date from history management", pe);
this.since = null;
}
}
}
}
/**
* Returns the total number of characters to receive in the history.
*
* @return total number of characters to receive in the history.
*/
public int getMaxChars() {
return maxChars;
}
/**
* Returns the total number of messages to receive in the history.
*
* @return the total number of messages to receive in the history.
*/
public int getMaxStanzas() {
return maxStanzas;
}
/**
* Returns the number of seconds to use to filter the messages received during that time.
* In other words, only the messages received in the last "X" seconds will be included in
* the history.
*
* @return the number of seconds to use to filter the messages received during that time.
*/
public int getSeconds() {
return seconds;
}
/**
* Returns the since date to use to filter the messages received during that time.
* In other words, only the messages received since the datetime specified will be
* included in the history.
*
* @return the since date to use to filter the messages received during that time.
*/
public Date getSince() {
return since;
}
/**
* Returns true if the history has been configured with some values.
*
* @return true if the history has been configured with some values.
*/
private boolean isConfigured() {
return maxChars > -1 || maxStanzas > -1 || seconds > -1 || since != null;
}
/**
* Sends the smallest amount of traffic that meets any combination of the requested criteria.
*
* @param joinRole the user that will receive the history.
* @param roomHistory the history of the room.
*/
public void sendHistory(LocalMUCRole joinRole, MUCRoomHistory roomHistory) {
if (!isConfigured()) {
Iterator history = roomHistory.getMessageHistory();
while (history.hasNext()) {
joinRole.send(history.next());
}
}
else {
if (getMaxChars() == 0) {
// The user requested to receive no history
return;
}
int accumulatedChars = 0;
int accumulatedStanzas = 0;
Element delayInformation;
LinkedList historyToSend = new LinkedList<>();
ListIterator iterator = roomHistory.getReverseMessageHistory();
while (iterator.hasPrevious()) {
Message message = iterator.previous();
// Update number of characters to send
String text = message.getBody() == null ? message.getSubject() : message.getBody();
if (text == null) {
// Skip this message since it has no body and no subject
continue;
}
accumulatedChars += text.length();
if (getMaxChars() > -1 && accumulatedChars > getMaxChars()) {
// Stop collecting history since we have exceded a limit
break;
}
// Update number of messages to send
accumulatedStanzas ++;
if (getMaxStanzas() > -1 && accumulatedStanzas > getMaxStanzas()) {
// Stop collecting history since we have exceded a limit
break;
}
if (getSeconds() > -1 || getSince() != null) {
delayInformation = message.getChildElement("delay", "urn:xmpp:delay");
try {
// Get the date when the historic message was sent
Date delayedDate = xmppDateTime.parseString(delayInformation.attributeValue("stamp"));
if (getSince() != null && delayedDate != null && delayedDate.before(getSince())) {
// Stop collecting history since we have exceded a limit
break;
}
if (getSeconds() > -1) {
Date current = new Date();
long diff = (current.getTime() - delayedDate.getTime()) / 1000;
if (getSeconds() <= diff) {
// Stop collecting history since we have exceded a limit
break;
}
}
}
catch (Exception e) {
Log.error("Error parsing date from historic message", e);
}
}
historyToSend.addFirst(message);
}
// Send the smallest amount of traffic to the user
for (Object aHistoryToSend : historyToSend) {
joinRole.send((Message) aHistoryToSend);
}
}
}
}