Commit 584973dd authored by Leon Roy's avatar Leon Roy Committed by leonroy

OF-664 - Monitoring archive shows null in room chat logs

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13627 b35dd754-fafc-0310-a699-88a17e54d16e
parent 7668d387
...@@ -50,594 +50,578 @@ import org.jivesoftware.openfire.user.UserNotFoundException; ...@@ -50,594 +50,578 @@ import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.NotFoundException; import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
/** /**
* Represents an IM conversation between two people. A conversation encompasses a * Represents an IM conversation between two people. A conversation encompasses a series of messages sent back and forth. It may cover a single topic
* series of messages sent back and forth. It may cover a single topic or several. * or several. The start of a conversation occurs when the first message between two users is sent. It ends when either:
* The start of a conversation occurs when the first message between two users is
* sent. It ends when either:
* <ul> * <ul>
* <li>No messages are sent between the users for a certain period of time (default of 10 * <li>No messages are sent between the users for a certain period of time (default of 10 minutes). The default value can be overridden by setting the
* minutes). The default value can be overridden by setting the Openfire property * Openfire property <tt>conversation.idleTime</tt>.</li>
* <tt>conversation.idleTime</tt>.</li> * <li>The total conversation time reaches a maximum value (default of 60 minutes). The default value can be overridden by setting the Openfire
* <li>The total conversation time reaches a maximum value (default of 60 minutes). * property <tt>conversation.maxTime</tt>. When the max time has been reached and additional messages are sent between the users, a new conversation
* The default value can be overridden by setting the Openfire property * will simply be started.</li>
* <tt>conversation.maxTime</tt>. When the max time has been reached and additional
* messages are sent between the users, a new conversation will simply be
* started.</li>
* </ul> * </ul>
* <p/> * <p/>
* Each conversation has a start time, date of the last message, and count of the * Each conversation has a start time, date of the last message, and count of the messages in the conversation. Conversations are specially marked if
* messages in the conversation. Conversations are specially marked if one of the * one of the participants is on an external server. If archiving is enabled, the actual messages in the conversation can be retrieved.
* participants is on an external server. If archiving is enabled, the actual messages in *
* the conversation can be retrieved.
*
* @author Matt Tucker * @author Matt Tucker
*/ */
@JiveID(50) @JiveID(50)
public class Conversation implements Externalizable { public class Conversation implements Externalizable {
private static final Logger Log = LoggerFactory.getLogger(Conversation.class); private static final Logger Log = LoggerFactory.getLogger(Conversation.class);
private static final String INSERT_CONVERSATION = private static final String INSERT_CONVERSATION = "INSERT INTO ofConversation(conversationID, room, isExternal, startDate, "
"INSERT INTO ofConversation(conversationID, room, isExternal, startDate, " + + "lastActivity, messageCount) VALUES (?,?,?,?,?,0)";
"lastActivity, messageCount) VALUES (?,?,?,?,?,0)"; private static final String INSERT_PARTICIPANT = "INSERT INTO ofConParticipant(conversationID, joinedDate, bareJID, jidResource, nickname) "
private static final String INSERT_PARTICIPANT = + "VALUES (?,?,?,?,?)";
"INSERT INTO ofConParticipant(conversationID, joinedDate, bareJID, jidResource, nickname) " + private static final String LOAD_CONVERSATION = "SELECT room, isExternal, startDate, lastActivity, messageCount "
"VALUES (?,?,?,?,?)"; + "FROM ofConversation WHERE conversationID=?";
private static final String LOAD_CONVERSATION = private static final String LOAD_PARTICIPANTS = "SELECT bareJID, jidResource, nickname, joinedDate, leftDate FROM ofConParticipant "
"SELECT room, isExternal, startDate, lastActivity, messageCount " + + "WHERE conversationID=? ORDER BY joinedDate";
"FROM ofConversation WHERE conversationID=?"; private static final String LOAD_MESSAGES = "SELECT fromJID, fromJIDResource, toJID, toJIDResource, sentDate, body FROM ofMessageArchive WHERE conversationID=? "
private static final String LOAD_PARTICIPANTS = + "ORDER BY sentDate";
"SELECT bareJID, jidResource, nickname, joinedDate, leftDate FROM ofConParticipant " +
"WHERE conversationID=? ORDER BY joinedDate"; private transient ConversationManager conversationManager;
private static final String LOAD_MESSAGES =
"SELECT fromJID, toJID, sentDate, body FROM ofMessageArchive WHERE conversationID=? " + private long conversationID = -1;
"ORDER BY sentDate"; private Map<String, UserParticipations> participants;
private boolean external;
private transient ConversationManager conversationManager; private Date startDate;
private Date lastActivity;
private long conversationID = -1; private int messageCount;
private Map<String, UserParticipations> participants; /**
private boolean external; * Room where the group conversion is taking place. For one-to-one chats there is no room so this variable will be null.
private Date startDate; */
private Date lastActivity; private JID room;
private int messageCount;
/** /**
* Room where the group conversion is taking place. For one-to-one chats * Do not use this constructor. It only exists for serialization purposes.
* there is no room so this variable will be null. */
*/ public Conversation() {
private JID room; }
/** /**
* Do not use this constructor. It only exists for serialization purposes. * Constructs a new one-to-one conversation.
*/ *
public Conversation() { * @param conversationManager
} * the ConversationManager.
* @param users
/** * the two participants in the conversation.
* Constructs a new one-to-one conversation. * @param external
* * true if the conversation includes a user on another server.
* @param conversationManager the ConversationManager. * @param startDate
* @param users the two participants in the conversation. * the starting date of the conversation.
* @param external true if the conversation includes a user on another server. */
* @param startDate the starting date of the conversation. public Conversation(ConversationManager conversationManager, Collection<JID> users, boolean external, Date startDate) {
*/ if (users.size() != 2) {
public Conversation(ConversationManager conversationManager, Collection<JID> users, throw new IllegalArgumentException("Illegal number of participants: " + users.size());
boolean external, Date startDate) { }
if (users.size() != 2) { this.conversationManager = conversationManager;
throw new IllegalArgumentException("Illegal number of participants: " + users.size()); this.participants = new HashMap<String, UserParticipations>(2);
} // Ensure that we're use the full JID of each participant.
this.conversationManager = conversationManager; for (JID user : users) {
this.participants = new HashMap<String, UserParticipations>(2); UserParticipations userParticipations = new UserParticipations(false);
// Ensure that we're use the full JID of each participant. userParticipations.addParticipation(new ConversationParticipation(startDate));
for (JID user : users) { participants.put(user.toString(), userParticipations);
UserParticipations userParticipations = new UserParticipations(false); }
userParticipations.addParticipation(new ConversationParticipation(startDate)); this.external = external;
participants.put(user.toString(), userParticipations); this.startDate = startDate;
} this.lastActivity = startDate;
this.external = external; // If archiving is enabled, insert the conversation into the database.
this.startDate = startDate; if (conversationManager.isMetadataArchivingEnabled()) {
this.lastActivity = startDate; try {
// If archiving is enabled, insert the conversation into the database. insertIntoDb();
if (conversationManager.isMetadataArchivingEnabled()) { } catch (Exception e) {
try { Log.error(e.getMessage(), e);
insertIntoDb(); }
} }
catch (Exception e) { }
Log.error(e.getMessage(), e);
} /**
} * Constructs a new group chat conversation that is taking place in a room.
} *
* @param conversationManager
/** * the ConversationManager.
* Constructs a new group chat conversation that is taking place in a room. * @param room
* * the JID of the room where the conversation is taking place.
* @param conversationManager the ConversationManager. * @param external
* @param room the JID of the room where the conversation is taking place. * true if the conversation includes a user on another server.
* @param external true if the conversation includes a user on another server. * @param startDate
* @param startDate the starting date of the conversation. * the starting date of the conversation.
*/ */
public Conversation(ConversationManager conversationManager, JID room, boolean external, Date startDate) { public Conversation(ConversationManager conversationManager, JID room, boolean external, Date startDate) {
this.conversationManager = conversationManager; this.conversationManager = conversationManager;
this.participants = new ConcurrentHashMap<String, UserParticipations>(); this.participants = new ConcurrentHashMap<String, UserParticipations>();
// Add list of existing room occupants as participants of this conversation // Add list of existing room occupants as participants of this conversation
MUCRoom mucRoom = XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService(room).getChatRoom(room.getNode()); MUCRoom mucRoom = XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService(room).getChatRoom(room.getNode());
if (mucRoom != null) { if (mucRoom != null) {
for (MUCRole role : mucRoom.getOccupants()) { for (MUCRole role : mucRoom.getOccupants()) {
UserParticipations userParticipations = new UserParticipations(true); UserParticipations userParticipations = new UserParticipations(true);
userParticipations.addParticipation(new ConversationParticipation(startDate, role.getNickname())); userParticipations.addParticipation(new ConversationParticipation(startDate, role.getNickname()));
participants.put(role.getUserAddress().toString(), userParticipations); participants.put(role.getUserAddress().toString(), userParticipations);
} }
} }
this.room = room; this.room = room;
this.external = external; this.external = external;
this.startDate = startDate; this.startDate = startDate;
this.lastActivity = startDate; this.lastActivity = startDate;
// If archiving is enabled, insert the conversation into the database. // If archiving is enabled, insert the conversation into the database.
if (conversationManager.isMetadataArchivingEnabled()) { if (conversationManager.isMetadataArchivingEnabled()) {
try { try {
insertIntoDb(); insertIntoDb();
} } catch (Exception e) {
catch (Exception e) { Log.error(e.getMessage(), e);
Log.error(e.getMessage(), e); }
} }
} }
}
/**
/** * Loads a conversation from the database.
* Loads a conversation from the database. *
* * @param conversationManager
* @param conversationManager the conversation manager. * the conversation manager.
* @param conversationID the ID of the conversation. * @param conversationID
* @throws NotFoundException if the conversation can't be loaded. * the ID of the conversation.
*/ * @throws NotFoundException
public Conversation(ConversationManager conversationManager, long conversationID) * if the conversation can't be loaded.
throws NotFoundException { */
this.conversationManager = conversationManager; public Conversation(ConversationManager conversationManager, long conversationID) throws NotFoundException {
this.conversationID = conversationID; this.conversationManager = conversationManager;
loadFromDb(); this.conversationID = conversationID;
} loadFromDb();
}
/**
* Returns the unique ID of the conversation. A unique ID is only meaningful when /**
* conversation archiving is enabled. Therefore, this method returns <tt>-1</tt> if * Returns the unique ID of the conversation. A unique ID is only meaningful when conversation archiving is enabled. Therefore, this method
* archiving is not turned on. * returns <tt>-1</tt> if archiving is not turned on.
* *
* @return the unique ID of the conversation, or <tt>-1</tt> if conversation * @return the unique ID of the conversation, or <tt>-1</tt> if conversation archiving is not enabled.
* archiving is not enabled. */
*/ public long getConversationID() {
public long getConversationID() { return conversationID;
return conversationID; }
}
/**
* Returns the JID of the room where the group conversation took place. If the conversation was a one-to-one chat then a <tt>null</tt> value is
/** * returned.
* Returns the JID of the room where the group conversation took place. If the conversation *
* was a one-to-one chat then a <tt>null</tt> value is returned. * @return the JID of room or null if this was a one-to-one chat.
* */
* @return the JID of room or null if this was a one-to-one chat. public JID getRoom() {
*/ return room;
public JID getRoom() { }
return room;
} /**
* Returns the conversation participants.
/** *
* Returns the conversation participants. * @return the two conversation participants. Returned JIDs are full JIDs.
* */
* @return the two conversation participants. Returned JIDs are full JIDs. public Collection<JID> getParticipants() {
*/ List<JID> users = new ArrayList<JID>();
public Collection<JID> getParticipants() { for (String key : participants.keySet()) {
List<JID> users = new ArrayList<JID>(); users.add(new JID(key));
for (String key : participants.keySet()) { }
users.add(new JID(key)); return users;
} }
return users;
} /**
* Returns the participations of the specified user (full JID) in this conversation. Each participation will hold the time when the user joined
/** * and left the conversation and the nickname if the room happened in a room.
* Returns the participations of the specified user (full JID) in this conversation. Each *
* participation will hold the time when the user joined and left the conversation and the * @param user
* nickname if the room happened in a room. * the full JID of the user.
* * @return the participations of the specified user (full JID) in this conversation.
* @param user the full JID of the user. */
* @return the participations of the specified user (full JID) in this conversation. public Collection<ConversationParticipation> getParticipations(JID user) {
*/ UserParticipations userParticipations = participants.get(user.toString());
public Collection<ConversationParticipation> getParticipations(JID user) { if (userParticipations == null) {
UserParticipations userParticipations = participants.get(user.toString()); return Collections.emptyList();
if (userParticipations == null) { }
return Collections.emptyList(); return userParticipations.getParticipations();
} }
return userParticipations.getParticipations();
} /**
* Returns true if one of the conversation participants is on an external server.
/** *
* Returns true if one of the conversation participants is on an external server. * @return true if one of the conversation participants is on an external server.
* */
* @return true if one of the conversation participants is on an external server. public boolean isExternal() {
*/ return external;
public boolean isExternal() { }
return external;
} /**
* Returns the starting timestamp of the conversation.
/** *
* Returns the starting timestamp of the conversation. * @return the start date.
* */
* @return the start date. public Date getStartDate() {
*/ return startDate;
public Date getStartDate() { }
return startDate;
} /**
* Returns the timestamp the last message was receieved.
/** *
* Returns the timestamp the last message was receieved. * @return the last activity.
* */
* @return the last activity. public Date getLastActivity() {
*/ return lastActivity;
public Date getLastActivity() { }
return lastActivity;
} /**
* Returns the number of messages that make up the conversation.
/** *
* Returns the number of messages that make up the conversation. * @return the message count.
* */
* @return the message count. public int getMessageCount() {
*/ return messageCount;
public int getMessageCount() { }
return messageCount;
} /**
* Returns the archived messages in the conversation. If message archiving is not enabled, this method will always return an empty collection.
/** * This method will only return messages that have already been batch-archived to the database; in other words, it does not provide a real-time
* Returns the archived messages in the conversation. If message archiving is not * view of new messages.
* enabled, this method will always return an empty collection. This method will only *
* return messages that have already been batch-archived to the database; in other * @return the archived messages in the conversation.
* words, it does not provide a real-time view of new messages. */
* public List<ArchivedMessage> getMessages() {
* @return the archived messages in the conversation. if (room == null && !conversationManager.isMessageArchivingEnabled()) {
*/ return Collections.emptyList();
public List<ArchivedMessage> getMessages() { } else if (room != null && !conversationManager.isRoomArchivingEnabled()) {
if (room == null && !conversationManager.isMessageArchivingEnabled()) { return Collections.emptyList();
return Collections.emptyList(); }
}
else if (room != null && !conversationManager.isRoomArchivingEnabled()) { List<ArchivedMessage> messages = new ArrayList<ArchivedMessage>();
return Collections.emptyList(); Connection con = null;
} PreparedStatement pstmt = null;
ResultSet rs = null;
List<ArchivedMessage> messages = new ArrayList<ArchivedMessage>(); try {
Connection con = null; con = DbConnectionManager.getConnection();
PreparedStatement pstmt = null; pstmt = con.prepareStatement(LOAD_MESSAGES);
ResultSet rs = null; pstmt.setLong(1, getConversationID());
try { rs = pstmt.executeQuery();
con = DbConnectionManager.getConnection(); while (rs.next()) {
pstmt = con.prepareStatement(LOAD_MESSAGES); JID fromJID = new JID(rs.getString(1));
pstmt.setLong(1, getConversationID()); String fromJIDResource = rs.getString(2);
rs = pstmt.executeQuery(); if (fromJIDResource != null && !"".equals(fromJIDResource)) {
while (rs.next()) { fromJID = new JID(rs.getString(1) + "/" + fromJIDResource);
JID fromJID = new JID(rs.getString(1)); }
JID toJID = new JID(rs.getString(2)); JID toJID = new JID(rs.getString(3));
Date date = new Date(rs.getLong(3)); String toJIDResource = rs.getString(4);
String body = DbConnectionManager.getLargeTextField(rs, 4); if (toJIDResource != null && !"".equals(toJIDResource)) {
messages.add(new ArchivedMessage(conversationID, fromJID, toJID, date, body, false)); toJID = new JID(rs.getString(1) + "/" + toJIDResource);
} }
} Date date = new Date(rs.getLong(5));
catch (SQLException sqle) { String body = DbConnectionManager.getLargeTextField(rs, 6);
Log.error(sqle.getMessage(), sqle); messages.add(new ArchivedMessage(conversationID, fromJID, toJID, date, body, false));
} }
finally { } catch (SQLException sqle) {
DbConnectionManager.closeConnection(rs, pstmt, con); Log.error(sqle.getMessage(), sqle);
} } finally {
// Add messages of users joining or leaving the group chat conversation DbConnectionManager.closeConnection(rs, pstmt, con);
if (room != null) { }
for (Map.Entry<String, UserParticipations> entry : participants.entrySet()) { // Add messages of users joining or leaving the group chat conversation
JID user = new JID(entry.getKey()); if (room != null) {
boolean anonymous = false; for (Map.Entry<String, UserParticipations> entry : participants.entrySet()) {
String name; JID user = new JID(entry.getKey());
try { boolean anonymous = false;
name = UserNameManager.getUserName(user); String name;
} try {
catch (UserNotFoundException e) { name = UserNameManager.getUserName(user);
name = user.toBareJID(); } catch (UserNotFoundException e) {
anonymous = true; name = user.toBareJID();
} anonymous = true;
for (ConversationParticipation participation : entry.getValue().getParticipations()) { }
if (participation.getJoined() == null) { for (ConversationParticipation participation : entry.getValue().getParticipations()) {
Log.warn("Found muc participant with no join date in conversation: " + conversationID); if (participation.getJoined() == null) {
continue; Log.warn("Found muc participant with no join date in conversation: " + conversationID);
} continue;
JID jid = new JID(room + "/" + participation.getNickname()); }
String joinBody; JID jid = new JID(room + "/" + participation.getNickname());
String leftBody; String joinBody;
if (anonymous) { String leftBody;
joinBody = LocaleUtils.getLocalizedString("muc.conversation.joined.anonymous", MonitoringConstants.NAME, if (anonymous) {
Arrays.asList(participation.getNickname())); joinBody = LocaleUtils.getLocalizedString("muc.conversation.joined.anonymous", MonitoringConstants.NAME,
leftBody = LocaleUtils.getLocalizedString("muc.conversation.left.anonymous", MonitoringConstants.NAME, Arrays.asList(participation.getNickname()));
Arrays.asList(participation.getNickname())); leftBody = LocaleUtils.getLocalizedString("muc.conversation.left.anonymous", MonitoringConstants.NAME,
} Arrays.asList(participation.getNickname()));
else { } else {
joinBody = LocaleUtils.getLocalizedString("muc.conversation.joined", MonitoringConstants.NAME, joinBody = LocaleUtils.getLocalizedString("muc.conversation.joined", MonitoringConstants.NAME,
Arrays.asList(participation.getNickname(), name)); Arrays.asList(participation.getNickname(), name));
leftBody = LocaleUtils.getLocalizedString("muc.conversation.left", MonitoringConstants.NAME, leftBody = LocaleUtils.getLocalizedString("muc.conversation.left", MonitoringConstants.NAME,
Arrays.asList(participation.getNickname(), name)); Arrays.asList(participation.getNickname(), name));
} }
messages.add( messages.add(new ArchivedMessage(conversationID, user, jid, participation.getJoined(), joinBody, true));
new ArchivedMessage(conversationID, user, jid, participation.getJoined(), joinBody, true)); if (participation.getLeft() != null) {
if (participation.getLeft() != null) { messages.add(new ArchivedMessage(conversationID, user, jid, participation.getLeft(), leftBody, true));
messages.add(new ArchivedMessage(conversationID, user, jid, participation.getLeft(), leftBody, }
true)); }
} }
} // Sort messages by sent date
} Collections.sort(messages, new Comparator<ArchivedMessage>() {
// Sort messages by sent date public int compare(ArchivedMessage o1, ArchivedMessage o2) {
Collections.sort(messages, new Comparator<ArchivedMessage>() { return o1.getSentDate().compareTo(o2.getSentDate());
public int compare(ArchivedMessage o1, ArchivedMessage o2) { }
return o1.getSentDate().compareTo(o2.getSentDate()); });
} }
}); return messages;
} }
return messages;
} @Override
@Override
public String toString() { public String toString() {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append("Conversation [").append(conversationID).append("]"); buf.append("Conversation [").append(conversationID).append("]");
if (room != null) { if (room != null) {
buf.append(" in room").append(room); buf.append(" in room").append(room);
} }
buf.append(" between ").append(participants); buf.append(" between ").append(participants);
buf.append(". started ").append(JiveGlobals.formatDateTime(startDate)); buf.append(". started ").append(JiveGlobals.formatDateTime(startDate));
buf.append(", last active ").append(JiveGlobals.formatDateTime(lastActivity)); buf.append(", last active ").append(JiveGlobals.formatDateTime(lastActivity));
buf.append(". Total messages: ").append(messageCount); buf.append(". Total messages: ").append(messageCount);
return buf.toString(); return buf.toString();
} }
/** /**
* Called when a new message for the conversation is received. Each time a new * Called when a new message for the conversation is received. Each time a new message is received, the last activity date will be updated and the
* message is received, the last activity date will be updated and the message * message count incremented.
* count incremented. *
* * @param entity
* @param entity JID of the entity that sent the message. * JID of the entity that sent the message.
* @param date the date the message was sent. * @param date
*/ * the date the message was sent.
synchronized void messageReceived(JID entity, Date date) { */
lastActivity = date; synchronized void messageReceived(JID entity, Date date) {
messageCount++; lastActivity = date;
} messageCount++;
}
synchronized void participantJoined(JID user, String nickname, long timestamp) {
// Add the sender of the message as a participant of this conversation. If the sender synchronized void participantJoined(JID user, String nickname, long timestamp) {
// was already a participant then he/she will appear just once. Rooms are never considered // Add the sender of the message as a participant of this conversation. If the sender
// as participants // was already a participant then he/she will appear just once. Rooms are never considered
UserParticipations userParticipations = participants.get(user.toString()); // as participants
if (userParticipations == null) { UserParticipations userParticipations = participants.get(user.toString());
userParticipations = new UserParticipations(true); if (userParticipations == null) {
participants.put(user.toString(), userParticipations); userParticipations = new UserParticipations(true);
} participants.put(user.toString(), userParticipations);
else { } else {
// Get last known participation and check that the user has finished it // Get last known participation and check that the user has finished it
ConversationParticipation lastParticipation = userParticipations.getRecentParticipation(); ConversationParticipation lastParticipation = userParticipations.getRecentParticipation();
if (lastParticipation != null && lastParticipation.getLeft() == null) { if (lastParticipation != null && lastParticipation.getLeft() == null) {
Log.warn("Found user that never left a previous conversation: " + user); Log.warn("Found user that never left a previous conversation: " + user);
lastParticipation.participationEnded(new Date(timestamp)); lastParticipation.participationEnded(new Date(timestamp));
// Queue storeage of updated participation information // Queue storeage of updated participation information
conversationManager.queueParticipantLeft(this, user, lastParticipation); conversationManager.queueParticipantLeft(this, user, lastParticipation);
} }
} }
ConversationParticipation newParticipation = new ConversationParticipation(new Date(timestamp), nickname); ConversationParticipation newParticipation = new ConversationParticipation(new Date(timestamp), nickname);
// Add element to the beginning of the list // Add element to the beginning of the list
userParticipations.addParticipation(newParticipation); userParticipations.addParticipation(newParticipation);
// If archiving is enabled, insert the conversation into the database (if not persistent yet). // If archiving is enabled, insert the conversation into the database (if not persistent yet).
if (conversationManager.isMetadataArchivingEnabled()) { if (conversationManager.isMetadataArchivingEnabled()) {
try { try {
if (conversationID == -1) { if (conversationID == -1) {
// Save new conversation to the database // Save new conversation to the database
insertIntoDb(); insertIntoDb();
} } else {
else { // Store new participation information
// Store new participation information insertIntoDb(user, nickname, timestamp);
insertIntoDb(user, nickname, timestamp); }
} } catch (Exception e) {
} Log.error(e.getMessage(), e);
catch (Exception e) { }
Log.error(e.getMessage(), e); }
} }
}
} synchronized void participantLeft(JID user, long timestamp) {
// Get the list of participations of the specified user
synchronized void participantLeft(JID user, long timestamp) { UserParticipations userParticipations = participants.get(user.toString());
// Get the list of participations of the specified user if (userParticipations == null) {
UserParticipations userParticipations = participants.get(user.toString()); Log.warn("Found user that left a conversation but never started it: " + user);
if (userParticipations == null) { } else {
Log.warn("Found user that left a conversation but never started it: " + user); // Get last known participation and check that the user has not finished it
} ConversationParticipation currentParticipation = userParticipations.getRecentParticipation();
else { if (currentParticipation == null || currentParticipation.getLeft() != null) {
// Get last known participation and check that the user has not finished it Log.warn("Found user that left a conversation but never started it: " + user);
ConversationParticipation currentParticipation = userParticipations.getRecentParticipation(); } else {
if (currentParticipation == null || currentParticipation.getLeft() != null) { currentParticipation.participationEnded(new Date(timestamp));
Log.warn("Found user that left a conversation but never started it: " + user); // Queue storeage of updated participation information
} conversationManager.queueParticipantLeft(this, user, currentParticipation);
else { }
currentParticipation.participationEnded(new Date(timestamp)); }
// Queue storeage of updated participation information }
conversationManager.queueParticipantLeft(this, user, currentParticipation);
} /**
} * Inserts a new conversation into the database.
} *
* @throws SQLException
/** * if an error occurs inserting the conversation.
* Inserts a new conversation into the database. */
* private void insertIntoDb() throws SQLException {
* @throws SQLException if an error occurs inserting the conversation. this.conversationID = SequenceManager.nextID(this);
*/ Connection con = null;
private void insertIntoDb() throws SQLException { boolean abortTransaction = false;
this.conversationID = SequenceManager.nextID(this); try {
Connection con = null; con = DbConnectionManager.getTransactionConnection();
boolean abortTransaction = false; PreparedStatement pstmt = con.prepareStatement(INSERT_CONVERSATION);
try { pstmt.setLong(1, conversationID);
con = DbConnectionManager.getTransactionConnection(); pstmt.setString(2, room == null ? null : room.toString());
PreparedStatement pstmt = con.prepareStatement(INSERT_CONVERSATION); pstmt.setInt(3, (external ? 1 : 0));
pstmt.setLong(1, conversationID); pstmt.setLong(4, startDate.getTime());
pstmt.setString(2, room == null ? null : room.toString()); pstmt.setLong(5, lastActivity.getTime());
pstmt.setInt(3, (external ? 1 : 0)); pstmt.executeUpdate();
pstmt.setLong(4, startDate.getTime()); pstmt.close();
pstmt.setLong(5, lastActivity.getTime());
pstmt.executeUpdate(); pstmt = con.prepareStatement(INSERT_PARTICIPANT);
pstmt.close(); for (Map.Entry<String, UserParticipations> entry : participants.entrySet()) {
JID user = new JID(entry.getKey());
pstmt = con.prepareStatement(INSERT_PARTICIPANT); for (ConversationParticipation participation : entry.getValue().getParticipations()) {
for (Map.Entry<String, UserParticipations> entry : participants.entrySet()) { pstmt.setLong(1, conversationID);
JID user = new JID(entry.getKey()); pstmt.setLong(2, participation.getJoined().getTime());
for (ConversationParticipation participation : entry.getValue().getParticipations()) { pstmt.setString(3, user.toBareJID());
pstmt.setLong(1, conversationID); pstmt.setString(4, user.getResource() == null ? "" : user.getResource());
pstmt.setLong(2, participation.getJoined().getTime()); pstmt.setString(5, participation.getNickname());
pstmt.setString(3, user.toBareJID()); pstmt.executeUpdate();
pstmt.setString(4, user.getResource() == null ? "" : user.getResource()); }
pstmt.setString(5, participation.getNickname()); }
pstmt.executeUpdate(); pstmt.close();
} } catch (SQLException sqle) {
} abortTransaction = true;
pstmt.close(); throw sqle;
} } finally {
catch (SQLException sqle) { DbConnectionManager.closeTransactionConnection(con, abortTransaction);
abortTransaction = true; }
throw sqle; }
}
finally { /**
DbConnectionManager.closeTransactionConnection(con, abortTransaction); * Adds a new conversation participant into the database.
} *
} * @param participant
* the full JID of the participant.
/** * @param nickname
* Adds a new conversation participant into the database. * nickname of the user in the room.
* * @param joined
* @param participant the full JID of the participant. * timestamp when user joined the conversation.
* @param nickname nickname of the user in the room. * @throws SQLException
* @param joined timestamp when user joined the conversation. * if an error occurs inserting the conversation.
* @throws SQLException if an error occurs inserting the conversation. */
*/ private void insertIntoDb(JID participant, String nickname, long joined) throws SQLException {
private void insertIntoDb(JID participant, String nickname, long joined) throws SQLException { Connection con = null;
Connection con = null; try {
try { con = DbConnectionManager.getConnection();
con = DbConnectionManager.getConnection(); PreparedStatement pstmt = con.prepareStatement(INSERT_PARTICIPANT);
PreparedStatement pstmt = con.prepareStatement(INSERT_PARTICIPANT); pstmt.setLong(1, conversationID);
pstmt.setLong(1, conversationID); pstmt.setLong(2, joined);
pstmt.setLong(2, joined); pstmt.setString(3, participant.toBareJID());
pstmt.setString(3, participant.toBareJID()); pstmt.setString(4, participant.getResource() == null ? "" : participant.getResource());
pstmt.setString(4, participant.getResource() == null ? "" : participant.getResource()); pstmt.setString(5, nickname);
pstmt.setString(5, nickname); pstmt.executeUpdate();
pstmt.executeUpdate(); pstmt.close();
pstmt.close(); } catch (SQLException sqle) {
} throw sqle;
catch (SQLException sqle) { } finally {
throw sqle; DbConnectionManager.closeConnection(con);
} }
finally { }
DbConnectionManager.closeConnection(con);
} private void loadFromDb() throws NotFoundException {
} Connection con = null;
PreparedStatement pstmt = null;
private void loadFromDb() throws NotFoundException { ResultSet rs = null;
Connection con = null; try {
PreparedStatement pstmt = null; con = DbConnectionManager.getConnection();
ResultSet rs = null; pstmt = con.prepareStatement(LOAD_CONVERSATION);
try { pstmt.setLong(1, conversationID);
con = DbConnectionManager.getConnection(); rs = pstmt.executeQuery();
pstmt = con.prepareStatement(LOAD_CONVERSATION); if (!rs.next()) {
pstmt.setLong(1, conversationID); throw new NotFoundException("Conversation not found: " + conversationID);
rs = pstmt.executeQuery(); }
if (!rs.next()) { this.room = rs.getString(1) == null ? null : new JID(rs.getString(1));
throw new NotFoundException("Conversation not found: " + conversationID); this.external = rs.getInt(2) == 1;
} this.startDate = new Date(rs.getLong(3));
this.room = rs.getString(1) == null ? null : new JID(rs.getString(1)); this.lastActivity = new Date(rs.getLong(4));
this.external = rs.getInt(2) == 1; this.messageCount = rs.getInt(5);
this.startDate = new Date(rs.getLong(3)); rs.close();
this.lastActivity = new Date(rs.getLong(4)); pstmt.close();
this.messageCount = rs.getInt(5);
rs.close(); this.participants = new ConcurrentHashMap<String, UserParticipations>();
pstmt.close(); pstmt = con.prepareStatement(LOAD_PARTICIPANTS);
pstmt.setLong(1, conversationID);
this.participants = new ConcurrentHashMap<String, UserParticipations>(); rs = pstmt.executeQuery();
pstmt = con.prepareStatement(LOAD_PARTICIPANTS); while (rs.next()) {
pstmt.setLong(1, conversationID); // Rebuild full JID of participant
rs = pstmt.executeQuery(); String baredJID = rs.getString(1);
while (rs.next()) { String resource = rs.getString(2);
// Rebuild full JID of participant JID fullJID = new JID("".equals(resource) ? baredJID : baredJID + "/" + resource);
String baredJID = rs.getString(1); // Rebuild joined and left time
String resource = rs.getString(2); ConversationParticipation participation = new ConversationParticipation(new Date(rs.getLong(4)), rs.getString(3));
JID fullJID = new JID("".equals(resource) ? baredJID : baredJID + "/" + resource); if (rs.getLong(5) > 0) {
// Rebuild joined and left time participation.participationEnded(new Date(rs.getLong(5)));
ConversationParticipation participation = }
new ConversationParticipation(new Date(rs.getLong(4)), rs.getString(3)); // Store participation data
if (rs.getLong(5) > 0) { UserParticipations userParticipations = participants.get(fullJID.toString());
participation.participationEnded(new Date(rs.getLong(5))); if (userParticipations == null) {
} userParticipations = new UserParticipations(room != null);
// Store participation data participants.put(fullJID.toString(), userParticipations);
UserParticipations userParticipations = participants.get(fullJID.toString()); }
if (userParticipations == null) { userParticipations.addParticipation(participation);
userParticipations = new UserParticipations(room != null); }
participants.put(fullJID.toString(), userParticipations); } catch (SQLException sqle) {
} Log.error(sqle.getMessage(), sqle);
userParticipations.addParticipation(participation); } finally {
} DbConnectionManager.closeConnection(rs, pstmt, con);
} }
catch (SQLException sqle) { }
Log.error(sqle.getMessage(), sqle);
} /**
finally { * Notification message inficating that conversation has finished so remaining participants should be marked that they left the conversation.
DbConnectionManager.closeConnection(rs, pstmt, con); *
} * @param nowDate
} * the date when the conversation was finished
*/
/** void conversationEnded(Date nowDate) {
* Notification message inficating that conversation has finished so remaining participants for (Map.Entry<String, UserParticipations> entry : participants.entrySet()) {
* should be marked that they left the conversation. ConversationParticipation currentParticipation = entry.getValue().getRecentParticipation();
* if (currentParticipation.getLeft() == null) {
* @param nowDate the date when the conversation was finished currentParticipation.participationEnded(nowDate);
*/ // Queue storage of updated participation information
void conversationEnded(Date nowDate) { conversationManager.queueParticipantLeft(this, new JID(entry.getKey()), currentParticipation);
for (Map.Entry<String, UserParticipations> entry : participants.entrySet()) { }
ConversationParticipation currentParticipation = entry.getValue().getRecentParticipation(); }
if (currentParticipation.getLeft() == null) { }
currentParticipation.participationEnded(nowDate);
// Queue storage of updated participation information public void writeExternal(ObjectOutput out) throws IOException {
conversationManager.queueParticipantLeft(this, new JID(entry.getKey()), currentParticipation); ExternalizableUtil.getInstance().writeLong(out, conversationID);
} ExternalizableUtil.getInstance().writeExternalizableMap(out, participants);
} ExternalizableUtil.getInstance().writeBoolean(out, external);
} ExternalizableUtil.getInstance().writeLong(out, startDate.getTime());
ExternalizableUtil.getInstance().writeLong(out, lastActivity.getTime());
public void writeExternal(ObjectOutput out) throws IOException { ExternalizableUtil.getInstance().writeInt(out, messageCount);
ExternalizableUtil.getInstance().writeLong(out, conversationID); ExternalizableUtil.getInstance().writeBoolean(out, room != null);
ExternalizableUtil.getInstance().writeExternalizableMap(out, participants); if (room != null) {
ExternalizableUtil.getInstance().writeBoolean(out, external); ExternalizableUtil.getInstance().writeSerializable(out, room);
ExternalizableUtil.getInstance().writeLong(out, startDate.getTime()); }
ExternalizableUtil.getInstance().writeLong(out, lastActivity.getTime()); }
ExternalizableUtil.getInstance().writeInt(out, messageCount);
ExternalizableUtil.getInstance().writeBoolean(out, room != null); public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
if (room != null) { MonitoringPlugin plugin = (MonitoringPlugin) XMPPServer.getInstance().getPluginManager().getPlugin(MonitoringConstants.NAME);
ExternalizableUtil.getInstance().writeSerializable(out, room); conversationManager = (ConversationManager) plugin.getModule(ConversationManager.class);
}
} this.participants = new ConcurrentHashMap<String, UserParticipations>();
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { conversationID = ExternalizableUtil.getInstance().readLong(in);
MonitoringPlugin plugin = (MonitoringPlugin) XMPPServer.getInstance().getPluginManager().getPlugin( ExternalizableUtil.getInstance().readExternalizableMap(in, participants, getClass().getClassLoader());
MonitoringConstants.NAME); external = ExternalizableUtil.getInstance().readBoolean(in);
conversationManager = (ConversationManager) plugin.getModule(ConversationManager.class); startDate = new Date(ExternalizableUtil.getInstance().readLong(in));
lastActivity = new Date(ExternalizableUtil.getInstance().readLong(in));
messageCount = ExternalizableUtil.getInstance().readInt(in);
this.participants = new ConcurrentHashMap<String, UserParticipations>(); if (ExternalizableUtil.getInstance().readBoolean(in)) {
room = (JID) ExternalizableUtil.getInstance().readSerializable(in);
conversationID = ExternalizableUtil.getInstance().readLong(in); }
ExternalizableUtil.getInstance().readExternalizableMap(in, participants, getClass().getClassLoader()); }
external = ExternalizableUtil.getInstance().readBoolean(in);
startDate = new Date(ExternalizableUtil.getInstance().readLong(in));
lastActivity = new Date(ExternalizableUtil.getInstance().readLong(in));
messageCount = ExternalizableUtil.getInstance().readInt(in);
if (ExternalizableUtil.getInstance().readBoolean(in)) {
room = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
}
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment