001: /**
002: * $RCSfile: HistoryRequest.java,v $
003: * $Revision: 2899 $
004: * $Date: 2005-09-28 15:30:42 -0300 (Wed, 28 Sep 2005) $
005: *
006: * Copyright (C) 2004 Jive Software. All rights reserved.
007: *
008: * This software is published under the terms of the GNU Public License (GPL),
009: * a copy of which is included in this distribution.
010: */package org.jivesoftware.openfire.muc;
011:
012: import org.dom4j.Element;
013: import org.jivesoftware.openfire.muc.spi.LocalMUCRole;
014: import org.jivesoftware.util.JiveConstants;
015: import org.jivesoftware.util.Log;
016: import org.xmpp.packet.Message;
017:
018: import java.text.DateFormat;
019: import java.text.ParseException;
020: import java.text.SimpleDateFormat;
021: import java.util.*;
022:
023: /**
024: * Represents the amount of history requested by an occupant while joining a room. There are
025: * basically four ways to control the amount of history that a user may receive. Those are: limit
026: * by the maximum limit of characters to receive, limit by a maximum number of stanzas to receive,
027: * limit to receive only the messages before a given date or of the last X seconds.<p>
028: *
029: * A user may combine any of these four methods. The idea is that the user will receive the smallest
030: * amount of traffic so the amount of history to collect will stop as soon as any of the requested
031: * method has reached its limit.
032: *
033: * @author Gaston Dombiak
034: */
035: public class HistoryRequest {
036:
037: private static final DateFormat formatter = new SimpleDateFormat(
038: JiveConstants.XMPP_DATETIME_FORMAT);
039: private static final DateFormat delayedFormatter = new SimpleDateFormat(
040: JiveConstants.XMPP_DELAY_DATETIME_FORMAT);
041: static {
042: delayedFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
043: formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
044: }
045:
046: private int maxChars = -1;
047: private int maxStanzas = -1;
048: private int seconds = -1;
049: private Date since;
050:
051: public HistoryRequest(Element userFragment) {
052: Element history = userFragment.element("history");
053: if (history != null) {
054: if (history.attribute("maxchars") != null) {
055: this .maxChars = Integer.parseInt(history
056: .attributeValue("maxchars"));
057: }
058: if (history.attribute("maxstanzas") != null) {
059: this .maxStanzas = Integer.parseInt(history
060: .attributeValue("maxstanzas"));
061: }
062: if (history.attribute("seconds") != null) {
063: this .seconds = Integer.parseInt(history
064: .attributeValue("seconds"));
065: }
066: if (history.attribute("since") != null) {
067: try {
068: // parse utc into Date
069: synchronized (formatter) {
070: this .since = formatter.parse(history
071: .attributeValue("since"));
072: }
073: } catch (ParseException pe) {
074: Log
075: .error(
076: "Error parsing date from history management",
077: pe);
078: this .since = null;
079: }
080: }
081: }
082: }
083:
084: /**
085: * Returns the total number of characters to receive in the history.
086: *
087: * @return total number of characters to receive in the history.
088: */
089: public int getMaxChars() {
090: return maxChars;
091: }
092:
093: /**
094: * Returns the total number of messages to receive in the history.
095: *
096: * @return the total number of messages to receive in the history.
097: */
098: public int getMaxStanzas() {
099: return maxStanzas;
100: }
101:
102: /**
103: * Returns the number of seconds to use to filter the messages received during that time.
104: * In other words, only the messages received in the last "X" seconds will be included in
105: * the history.
106: *
107: * @return the number of seconds to use to filter the messages received during that time.
108: */
109: public int getSeconds() {
110: return seconds;
111: }
112:
113: /**
114: * Returns the since date to use to filter the messages received during that time.
115: * In other words, only the messages received since the datetime specified will be
116: * included in the history.
117: *
118: * @return the since date to use to filter the messages received during that time.
119: */
120: public Date getSince() {
121: return since;
122: }
123:
124: /**
125: * Returns true if the history has been configured with some values.
126: *
127: * @return true if the history has been configured with some values.
128: */
129: private boolean isConfigured() {
130: return maxChars > -1 || maxStanzas > -1 || seconds > -1
131: || since != null;
132: }
133:
134: /**
135: * Sends the smallest amount of traffic that meets any combination of the requested criteria.
136: *
137: * @param joinRole the user that will receive the history.
138: * @param roomHistory the history of the room.
139: */
140: public void sendHistory(LocalMUCRole joinRole,
141: MUCRoomHistory roomHistory) {
142: if (!isConfigured()) {
143: Iterator history = roomHistory.getMessageHistory();
144: while (history.hasNext()) {
145: joinRole.send((Message) history.next());
146: }
147: } else {
148: if (getMaxChars() == 0) {
149: // The user requested to receive no history
150: return;
151: }
152: Message message;
153: int accumulatedChars = 0;
154: int accumulatedStanzas = 0;
155: Element delayInformation;
156: LinkedList historyToSend = new LinkedList();
157: ListIterator iterator = roomHistory
158: .getReverseMessageHistory();
159: while (iterator.hasPrevious()) {
160: message = (Message) iterator.previous();
161: // Update number of characters to send
162: String text = message.getBody() == null ? message
163: .getSubject() : message.getBody();
164: if (text == null) {
165: // Skip this message since it has no body and no subject
166: continue;
167: }
168: accumulatedChars += text.length();
169: if (getMaxChars() > -1
170: && accumulatedChars > getMaxChars()) {
171: // Stop collecting history since we have exceded a limit
172: break;
173: }
174: // Update number of messages to send
175: accumulatedStanzas++;
176: if (getMaxStanzas() > -1
177: && accumulatedStanzas > getMaxStanzas()) {
178: // Stop collecting history since we have exceded a limit
179: break;
180: }
181:
182: if (getSeconds() > -1 || getSince() != null) {
183: delayInformation = message.getChildElement("x",
184: "jabber:x:delay");
185: try {
186: // Get the date when the historic message was sent
187: Date delayedDate = null;
188: synchronized (delayedFormatter) {
189: delayedDate = delayedFormatter
190: .parse(delayInformation
191: .attributeValue("stamp"));
192: }
193: if (getSince() != null
194: && delayedDate.before(getSince())) {
195: // Stop collecting history since we have exceded a limit
196: break;
197: }
198: if (getSeconds() > -1) {
199: Date current = new Date();
200: long diff = (current.getTime() - delayedDate
201: .getTime()) / 1000;
202: if (getSeconds() <= diff) {
203: // Stop collecting history since we have exceded a limit
204: break;
205: }
206: }
207: } catch (Exception e) {
208: Log
209: .error(
210: "Error parsing date from historic message",
211: e);
212: }
213:
214: }
215:
216: historyToSend.addFirst(message);
217: }
218: // Send the smallest amount of traffic to the user
219: Iterator history = historyToSend.iterator();
220: while (history.hasNext()) {
221: joinRole.send((Message) history.next());
222: }
223: }
224: }
225: }
|