0001: /**
0002: * $RCSfile$
0003: * $Revision: 1623 $
0004: * $Date: 2005-07-12 18:40:57 -0300 (Tue, 12 Jul 2005) $
0005: *
0006: * Copyright (C) 2004 Jive Software. All rights reserved.
0007: *
0008: * This software is published under the terms of the GNU Public License (GPL),
0009: * a copy of which is included in this distribution.
0010: */package org.jivesoftware.openfire.muc.spi;
0011:
0012: import org.jivesoftware.database.DbConnectionManager;
0013: import org.jivesoftware.openfire.PacketRouter;
0014: import org.jivesoftware.openfire.muc.MUCRole;
0015: import org.jivesoftware.openfire.muc.MUCRoom;
0016: import org.jivesoftware.openfire.muc.MultiUserChatServer;
0017: import org.jivesoftware.util.Log;
0018: import org.jivesoftware.util.StringUtils;
0019:
0020: import java.sql.Connection;
0021: import java.sql.PreparedStatement;
0022: import java.sql.ResultSet;
0023: import java.sql.SQLException;
0024: import java.util.*;
0025:
0026: /**
0027: * A manager responsible for ensuring room persistence. There are different ways to make a room
0028: * persistent. The first attempt will be to save the room in a relation database. If for some reason
0029: * the room can't be saved in the database an alternative repository will be used to save the room
0030: * such as XML files.<p>
0031: *
0032: * After the problem with the database has been solved, the information saved in the XML files will
0033: * be moved to the database.
0034: *
0035: * @author Gaston Dombiak
0036: */
0037: public class MUCPersistenceManager {
0038:
0039: private static final String GET_RESERVED_NAME = "SELECT nickname FROM mucMember WHERE roomID=? AND jid=?";
0040: private static final String LOAD_ROOM = "SELECT roomID, creationDate, modificationDate, naturalName, description, lockedDate, "
0041: + "emptyDate, canChangeSubject, maxUsers, publicRoom, moderated, membersOnly, canInvite, "
0042: + "roomPassword, canDiscoverJID, logEnabled, subject, rolesToBroadcast, useReservedNick, "
0043: + "canChangeNick, canRegister FROM mucRoom WHERE name=?";
0044: private static final String LOAD_AFFILIATIONS = "SELECT jid, affiliation FROM mucAffiliation WHERE roomID=?";
0045: private static final String LOAD_MEMBERS = "SELECT jid, nickname FROM mucMember WHERE roomID=?";
0046: private static final String LOAD_HISTORY = "SELECT sender, nickname, logTime, subject, body FROM mucConversationLog "
0047: + "WHERE logTime>? AND roomID=? AND (nickname IS NOT NULL OR subject IS NOT NULL) ORDER BY logTime";
0048: private static final String LOAD_ALL_ROOMS = "SELECT roomID, creationDate, modificationDate, name, naturalName, description, "
0049: + "lockedDate, emptyDate, canChangeSubject, maxUsers, publicRoom, moderated, membersOnly, "
0050: + "canInvite, roomPassword, canDiscoverJID, logEnabled, subject, rolesToBroadcast, "
0051: + "useReservedNick, canChangeNick, canRegister "
0052: + "FROM mucRoom WHERE emptyDate IS NULL or emptyDate > ?";
0053: private static final String LOAD_ALL_AFFILIATIONS = "SELECT roomID,jid,affiliation FROM mucAffiliation";
0054: private static final String LOAD_ALL_MEMBERS = "SELECT roomID,jid, nickname FROM mucMember";
0055: private static final String LOAD_ALL_HISTORY = "SELECT roomID, sender, nickname, logTime, subject, body FROM mucConversationLog "
0056: + "WHERE logTime>? AND (nickname IS NOT NULL OR subject IS NOT NULL) ORDER BY logTime";
0057: private static final String UPDATE_ROOM = "UPDATE mucRoom SET modificationDate=?, naturalName=?, description=?, "
0058: + "canChangeSubject=?, maxUsers=?, publicRoom=?, moderated=?, membersOnly=?, "
0059: + "canInvite=?, roomPassword=?, canDiscoverJID=?, logEnabled=?, rolesToBroadcast=?, "
0060: + "useReservedNick=?, canChangeNick=?, canRegister=? WHERE roomID=?";
0061: private static final String ADD_ROOM = "INSERT INTO mucRoom (roomID, creationDate, modificationDate, name, naturalName, "
0062: + "description, lockedDate, emptyDate, canChangeSubject, maxUsers, publicRoom, moderated, "
0063: + "membersOnly, canInvite, roomPassword, canDiscoverJID, logEnabled, subject, "
0064: + "rolesToBroadcast, useReservedNick, canChangeNick, canRegister) VALUES (?,?,?,?,?,?,?,?,"
0065: + "?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
0066: private static final String UPDATE_SUBJECT = "UPDATE mucRoom SET subject=? WHERE roomID=?";
0067: private static final String UPDATE_LOCK = "UPDATE mucRoom SET lockedDate=? WHERE roomID=?";
0068: private static final String UPDATE_EMPTYDATE = "UPDATE mucRoom SET emptyDate=? WHERE roomID=?";
0069: private static final String DELETE_ROOM = "DELETE FROM mucRoom WHERE roomID=?";
0070: private static final String DELETE_AFFILIATIONS = "DELETE FROM mucAffiliation WHERE roomID=?";
0071: private static final String DELETE_MEMBERS = "DELETE FROM mucMember WHERE roomID=?";
0072: private static final String ADD_MEMBER = "INSERT INTO mucMember (roomID,jid,nickname) VALUES (?,?,?)";
0073: private static final String UPDATE_MEMBER = "UPDATE mucMember SET nickname=? WHERE roomID=? AND jid=?";
0074: private static final String DELETE_MEMBER = "DELETE FROM mucMember WHERE roomID=? AND jid=?";
0075: private static final String ADD_AFFILIATION = "INSERT INTO mucAffiliation (roomID,jid,affiliation) VALUES (?,?,?)";
0076: private static final String UPDATE_AFFILIATION = "UPDATE mucAffiliation SET affiliation=? WHERE roomID=? AND jid=?";
0077: private static final String DELETE_AFFILIATION = "DELETE FROM mucAffiliation WHERE roomID=? AND jid=?";
0078:
0079: private static final String ADD_CONVERSATION_LOG = "INSERT INTO mucConversationLog (roomID,sender,nickname,logTime,subject,body) "
0080: + "VALUES (?,?,?,?,?,?)";
0081:
0082: /**
0083: * Returns the reserved room nickname for the bare JID in a given room or null if none.
0084: *
0085: * @param room the room where the user would like to obtain his reserved nickname.
0086: * @param bareJID The bare jid of the user of which you'd like to obtain his reserved nickname.
0087: * @return the reserved room nickname for the bare JID or null if none.
0088: */
0089: public static String getReservedNickname(MUCRoom room,
0090: String bareJID) {
0091: Connection con = null;
0092: PreparedStatement pstmt = null;
0093: String answer = null;
0094: try {
0095: con = DbConnectionManager.getConnection();
0096: pstmt = con.prepareStatement(GET_RESERVED_NAME);
0097: pstmt.setLong(1, room.getID());
0098: pstmt.setString(2, bareJID);
0099: ResultSet rs = pstmt.executeQuery();
0100: if (rs.next()) {
0101: answer = rs.getString(1);
0102: }
0103: rs.close();
0104: } catch (SQLException sqle) {
0105: Log.error(sqle);
0106: } finally {
0107: try {
0108: if (pstmt != null)
0109: pstmt.close();
0110: } catch (Exception e) {
0111: Log.error(e);
0112: }
0113: try {
0114: if (con != null)
0115: con.close();
0116: } catch (Exception e) {
0117: Log.error(e);
0118: }
0119: }
0120: return answer;
0121: }
0122:
0123: /**
0124: * Loads the room configuration from the database if the room was persistent.
0125: *
0126: * @param room the room to load from the database if persistent
0127: */
0128: public static void loadFromDB(LocalMUCRoom room) {
0129: Connection con = null;
0130: PreparedStatement pstmt = null;
0131: try {
0132: con = DbConnectionManager.getConnection();
0133: pstmt = con.prepareStatement(LOAD_ROOM);
0134: pstmt.setString(1, room.getName());
0135: ResultSet rs = pstmt.executeQuery();
0136: if (!rs.next()) {
0137: throw new IllegalArgumentException("Room "
0138: + room.getName()
0139: + " was not found in the database.");
0140: }
0141: room.setID(rs.getLong(1));
0142: room.setCreationDate(new Date(Long.parseLong(rs
0143: .getString(2).trim()))); // creation date
0144: room.setModificationDate(new Date(Long.parseLong(rs
0145: .getString(3).trim()))); // modification date
0146: room.setNaturalLanguageName(rs.getString(4));
0147: room.setDescription(rs.getString(5));
0148: room.setLockedDate(new Date(Long.parseLong(rs.getString(6)
0149: .trim())));
0150: if (rs.getString(7) != null) {
0151: room.setEmptyDate(new Date(Long.parseLong(rs.getString(
0152: 7).trim())));
0153: } else {
0154: room.setEmptyDate(null);
0155: }
0156: room.setCanOccupantsChangeSubject(rs.getInt(8) == 1 ? true
0157: : false);
0158: room.setMaxUsers(rs.getInt(9));
0159: room.setPublicRoom(rs.getInt(10) == 1 ? true : false);
0160: room.setModerated(rs.getInt(11) == 1 ? true : false);
0161: room.setMembersOnly(rs.getInt(12) == 1 ? true : false);
0162: room.setCanOccupantsInvite(rs.getInt(13) == 1 ? true
0163: : false);
0164: room.setPassword(rs.getString(14));
0165: room.setCanAnyoneDiscoverJID(rs.getInt(15) == 1 ? true
0166: : false);
0167: room.setLogEnabled(rs.getInt(16) == 1 ? true : false);
0168: room.setSubject(rs.getString(17));
0169: List<String> rolesToBroadcast = new ArrayList<String>();
0170: String roles = Integer.toBinaryString(rs.getInt(18));
0171: if (roles.charAt(0) == '1') {
0172: rolesToBroadcast.add("moderator");
0173: }
0174: if (roles.length() > 1 && roles.charAt(1) == '1') {
0175: rolesToBroadcast.add("participant");
0176: }
0177: if (roles.length() > 2 && roles.charAt(2) == '1') {
0178: rolesToBroadcast.add("visitor");
0179: }
0180: room.setRolesToBroadcastPresence(rolesToBroadcast);
0181: room.setLoginRestrictedToNickname(rs.getInt(19) == 1 ? true
0182: : false);
0183: room.setChangeNickname(rs.getInt(20) == 1 ? true : false);
0184: room.setRegistrationEnabled(rs.getInt(21) == 1 ? true
0185: : false);
0186: room.setPersistent(true);
0187: rs.close();
0188: pstmt.close();
0189:
0190: pstmt = con.prepareStatement(LOAD_HISTORY);
0191: // Recreate the history until two days ago
0192: long from = System.currentTimeMillis() - (86400000 * 2);
0193: pstmt
0194: .setString(1, StringUtils.dateToMillis(new Date(
0195: from)));
0196: pstmt.setLong(2, room.getID());
0197: rs = pstmt.executeQuery();
0198: while (rs.next()) {
0199: String senderJID = rs.getString(1);
0200: String nickname = rs.getString(2);
0201: Date sentDate = new Date(Long.parseLong(rs.getString(3)
0202: .trim()));
0203: String subject = rs.getString(4);
0204: String body = rs.getString(5);
0205: // Recreate the history only for the rooms that have the conversation logging
0206: // enabled
0207: if (room.isLogEnabled()) {
0208: room.getRoomHistory().addOldMessage(senderJID,
0209: nickname, sentDate, subject, body);
0210: }
0211: }
0212: rs.close();
0213: pstmt.close();
0214:
0215: // If the room does not include the last subject in the history then recreate one if
0216: // possible
0217: if (!room.getRoomHistory().hasChangedSubject()
0218: && room.getSubject() != null
0219: && room.getSubject().length() > 0) {
0220: room.getRoomHistory().addOldMessage(
0221: room.getRole().getRoleAddress().toString(),
0222: null, room.getModificationDate(),
0223: room.getSubject(), null);
0224: }
0225:
0226: pstmt = con.prepareStatement(LOAD_AFFILIATIONS);
0227: pstmt.setLong(1, room.getID());
0228: rs = pstmt.executeQuery();
0229: while (rs.next()) {
0230: String jid = rs.getString(1);
0231: MUCRole.Affiliation affiliation = MUCRole.Affiliation
0232: .valueOf(rs.getInt(2));
0233: try {
0234: switch (affiliation) {
0235: case owner:
0236: room.addOwner(jid, room.getRole());
0237: break;
0238: case admin:
0239: room.addAdmin(jid, room.getRole());
0240: break;
0241: case outcast:
0242: room.addOutcast(jid, null, room.getRole());
0243: break;
0244: default:
0245: Log
0246: .error("Unkown affiliation value "
0247: + affiliation + " for user "
0248: + jid + " in persistent room "
0249: + room.getID());
0250: }
0251: } catch (Exception e) {
0252: Log.error(e);
0253: }
0254: }
0255: rs.close();
0256: pstmt.close();
0257:
0258: pstmt = con.prepareStatement(LOAD_MEMBERS);
0259: pstmt.setLong(1, room.getID());
0260: rs = pstmt.executeQuery();
0261: while (rs.next()) {
0262: try {
0263: room.addMember(rs.getString(1), rs.getString(2),
0264: room.getRole());
0265: } catch (Exception e) {
0266: Log.error(e);
0267: }
0268: }
0269: rs.close();
0270: // Set now that the room's configuration is updated in the database. Note: We need to
0271: // set this now since otherwise the room's affiliations will be saved to the database
0272: // "again" while adding them to the room!
0273: room.setSavedToDB(true);
0274: if (room.getEmptyDate() == null) {
0275: // The service process was killed somehow while the room was being used. Since
0276: // the room won't have occupants at this time we need to set the best date when
0277: // the last occupant left the room that we can
0278: room.setEmptyDate(new Date());
0279: }
0280: } catch (SQLException sqle) {
0281: Log.error(sqle);
0282: } finally {
0283: try {
0284: if (pstmt != null)
0285: pstmt.close();
0286: } catch (Exception e) {
0287: Log.error(e);
0288: }
0289: try {
0290: if (con != null)
0291: con.close();
0292: } catch (Exception e) {
0293: Log.error(e);
0294: }
0295: }
0296: }
0297:
0298: /**
0299: * Save the room configuration to the DB.
0300: *
0301: * @param room The room to save its configuration.
0302: */
0303: public static void saveToDB(LocalMUCRoom room) {
0304: Connection con = null;
0305: PreparedStatement pstmt = null;
0306: try {
0307: con = DbConnectionManager.getConnection();
0308: if (room.wasSavedToDB()) {
0309: pstmt = con.prepareStatement(UPDATE_ROOM);
0310: pstmt.setString(1, StringUtils.dateToMillis(room
0311: .getModificationDate()));
0312: pstmt.setString(2, room.getNaturalLanguageName());
0313: pstmt.setString(3, room.getDescription());
0314: pstmt.setInt(4, (room.canOccupantsChangeSubject() ? 1
0315: : 0));
0316: pstmt.setInt(5, room.getMaxUsers());
0317: pstmt.setInt(6, (room.isPublicRoom() ? 1 : 0));
0318: pstmt.setInt(7, (room.isModerated() ? 1 : 0));
0319: pstmt.setInt(8, (room.isMembersOnly() ? 1 : 0));
0320: pstmt.setInt(9, (room.canOccupantsInvite() ? 1 : 0));
0321: pstmt.setString(10, room.getPassword());
0322: pstmt.setInt(11, (room.canAnyoneDiscoverJID() ? 1 : 0));
0323: pstmt.setInt(12, (room.isLogEnabled() ? 1 : 0));
0324: pstmt.setInt(13, marshallRolesToBroadcast(room));
0325: pstmt.setInt(14,
0326: (room.isLoginRestrictedToNickname() ? 1 : 0));
0327: pstmt.setInt(15, (room.canChangeNickname() ? 1 : 0));
0328: pstmt
0329: .setInt(16, (room.isRegistrationEnabled() ? 1
0330: : 0));
0331: pstmt.setLong(17, room.getID());
0332: pstmt.executeUpdate();
0333: } else {
0334: pstmt = con.prepareStatement(ADD_ROOM);
0335: pstmt.setLong(1, room.getID());
0336: pstmt.setString(2, StringUtils.dateToMillis(room
0337: .getCreationDate()));
0338: pstmt.setString(3, StringUtils.dateToMillis(room
0339: .getModificationDate()));
0340: pstmt.setString(4, room.getName());
0341: pstmt.setString(5, room.getNaturalLanguageName());
0342: pstmt.setString(6, room.getDescription());
0343: pstmt.setString(7, StringUtils.dateToMillis(room
0344: .getLockedDate()));
0345: Date emptyDate = room.getEmptyDate();
0346: if (emptyDate == null) {
0347: pstmt.setString(8, null);
0348: } else {
0349: pstmt.setString(8, StringUtils
0350: .dateToMillis(emptyDate));
0351: }
0352: pstmt.setInt(9, (room.canOccupantsChangeSubject() ? 1
0353: : 0));
0354: pstmt.setInt(10, room.getMaxUsers());
0355: pstmt.setInt(11, (room.isPublicRoom() ? 1 : 0));
0356: pstmt.setInt(12, (room.isModerated() ? 1 : 0));
0357: pstmt.setInt(13, (room.isMembersOnly() ? 1 : 0));
0358: pstmt.setInt(14, (room.canOccupantsInvite() ? 1 : 0));
0359: pstmt.setString(15, room.getPassword());
0360: pstmt.setInt(16, (room.canAnyoneDiscoverJID() ? 1 : 0));
0361: pstmt.setInt(17, (room.isLogEnabled() ? 1 : 0));
0362: pstmt.setString(18, room.getSubject());
0363: pstmt.setInt(19, marshallRolesToBroadcast(room));
0364: pstmt.setInt(20,
0365: (room.isLoginRestrictedToNickname() ? 1 : 0));
0366: pstmt.setInt(21, (room.canChangeNickname() ? 1 : 0));
0367: pstmt
0368: .setInt(22, (room.isRegistrationEnabled() ? 1
0369: : 0));
0370: pstmt.executeUpdate();
0371: }
0372: } catch (SQLException sqle) {
0373: Log.error(sqle);
0374: } finally {
0375: try {
0376: if (pstmt != null)
0377: pstmt.close();
0378: } catch (Exception e) {
0379: Log.error(e);
0380: }
0381: try {
0382: if (con != null)
0383: con.close();
0384: } catch (Exception e) {
0385: Log.error(e);
0386: }
0387: }
0388: }
0389:
0390: /**
0391: * Removes the room configuration and its affiliates from the database.
0392: *
0393: * @param room the room to remove from the database.
0394: */
0395: public static void deleteFromDB(MUCRoom room) {
0396: if (!room.isPersistent() || !room.wasSavedToDB()) {
0397: return;
0398: }
0399: Connection con = null;
0400: PreparedStatement pstmt = null;
0401: boolean abortTransaction = false;
0402: try {
0403: con = DbConnectionManager.getTransactionConnection();
0404: pstmt = con.prepareStatement(DELETE_AFFILIATIONS);
0405: pstmt.setLong(1, room.getID());
0406: pstmt.executeUpdate();
0407: pstmt.close();
0408:
0409: pstmt = con.prepareStatement(DELETE_MEMBERS);
0410: pstmt.setLong(1, room.getID());
0411: pstmt.executeUpdate();
0412: pstmt.close();
0413:
0414: pstmt = con.prepareStatement(DELETE_ROOM);
0415: pstmt.setLong(1, room.getID());
0416: pstmt.executeUpdate();
0417:
0418: // Update the room (in memory) to indicate the it's no longer in the database.
0419: room.setSavedToDB(false);
0420: } catch (SQLException sqle) {
0421: Log.error(sqle);
0422: abortTransaction = true;
0423: } finally {
0424: try {
0425: if (pstmt != null)
0426: pstmt.close();
0427: } catch (Exception e) {
0428: Log.error(e);
0429: }
0430: DbConnectionManager.closeTransactionConnection(con,
0431: abortTransaction);
0432: }
0433: }
0434:
0435: /**
0436: * Loads all the rooms that had occupants after a given date from the database. This query
0437: * will be executed only when the service is starting up.
0438: *
0439: * @param chatserver the chat server that will hold the loaded rooms.
0440: * @param emptyDate rooms that hadn't been used before this date won't be loaded.
0441: * @param packetRouter the PacketRouter that loaded rooms will use to send packets.
0442: * @return a collection with all the persistent rooms.
0443: */
0444: public static Collection<LocalMUCRoom> loadRoomsFromDB(
0445: MultiUserChatServer chatserver, Date emptyDate,
0446: PacketRouter packetRouter) {
0447: Connection con = null;
0448: PreparedStatement pstmt = null;
0449: Map<Long, LocalMUCRoom> rooms = new HashMap<Long, LocalMUCRoom>();
0450: try {
0451: con = DbConnectionManager.getConnection();
0452: pstmt = con.prepareStatement(LOAD_ALL_ROOMS);
0453: pstmt.setString(1, StringUtils.dateToMillis(emptyDate));
0454: ResultSet rs = pstmt.executeQuery();
0455: LocalMUCRoom room = null;
0456: while (rs.next()) {
0457: room = new LocalMUCRoom(chatserver, rs.getString(4),
0458: packetRouter);
0459: room.setID(rs.getLong(1));
0460: room.setCreationDate(new Date(Long.parseLong(rs
0461: .getString(2).trim()))); // creation date
0462: room.setModificationDate(new Date(Long.parseLong(rs
0463: .getString(3).trim()))); // modification date
0464: room.setNaturalLanguageName(rs.getString(5));
0465: room.setDescription(rs.getString(6));
0466: room.setLockedDate(new Date(Long.parseLong(rs
0467: .getString(7).trim())));
0468: if (rs.getString(8) != null) {
0469: room.setEmptyDate(new Date(Long.parseLong(rs
0470: .getString(8).trim())));
0471: } else {
0472: room.setEmptyDate(null);
0473: }
0474: room
0475: .setCanOccupantsChangeSubject(rs.getInt(9) == 1 ? true
0476: : false);
0477: room.setMaxUsers(rs.getInt(10));
0478: room.setPublicRoom(rs.getInt(11) == 1 ? true : false);
0479: room.setModerated(rs.getInt(12) == 1 ? true : false);
0480: room.setMembersOnly(rs.getInt(13) == 1 ? true : false);
0481: room.setCanOccupantsInvite(rs.getInt(14) == 1 ? true
0482: : false);
0483: room.setPassword(rs.getString(15));
0484: room.setCanAnyoneDiscoverJID(rs.getInt(16) == 1 ? true
0485: : false);
0486: room.setLogEnabled(rs.getInt(17) == 1 ? true : false);
0487: room.setSubject(rs.getString(18));
0488: List<String> rolesToBroadcast = new ArrayList<String>();
0489: String roles = Integer.toBinaryString(rs.getInt(19));
0490: if (roles.charAt(0) == '1') {
0491: rolesToBroadcast.add("moderator");
0492: }
0493: if (roles.length() > 1 && roles.charAt(1) == '1') {
0494: rolesToBroadcast.add("participant");
0495: }
0496: if (roles.length() > 2 && roles.charAt(2) == '1') {
0497: rolesToBroadcast.add("visitor");
0498: }
0499: room.setRolesToBroadcastPresence(rolesToBroadcast);
0500: room
0501: .setLoginRestrictedToNickname(rs.getInt(20) == 1 ? true
0502: : false);
0503: room.setChangeNickname(rs.getInt(21) == 1 ? true
0504: : false);
0505: room.setRegistrationEnabled(rs.getInt(22) == 1 ? true
0506: : false);
0507: room.setPersistent(true);
0508: rooms.put(room.getID(), room);
0509: }
0510: rs.close();
0511: pstmt.close();
0512:
0513: pstmt = con.prepareStatement(LOAD_ALL_HISTORY);
0514: // Recreate the history until two days ago
0515: long from = System.currentTimeMillis() - (86400000 * 2);
0516: pstmt
0517: .setString(1, StringUtils.dateToMillis(new Date(
0518: from)));
0519: // Load the rooms conversations from the last two days
0520: rs = pstmt.executeQuery();
0521: while (rs.next()) {
0522: room = (LocalMUCRoom) rooms.get(rs.getLong(1));
0523: // Skip to the next position if the room does not exist
0524: if (room == null) {
0525: continue;
0526: }
0527: String senderJID = rs.getString(2);
0528: String nickname = rs.getString(3);
0529: Date sentDate = new Date(Long.parseLong(rs.getString(4)
0530: .trim()));
0531: String subject = rs.getString(5);
0532: String body = rs.getString(6);
0533: try {
0534: // Recreate the history only for the rooms that have the conversation logging
0535: // enabled
0536: if (room.isLogEnabled()) {
0537: room.getRoomHistory().addOldMessage(senderJID,
0538: nickname, sentDate, subject, body);
0539: }
0540: } catch (Exception e) {
0541: Log.error(e);
0542: }
0543: }
0544: rs.close();
0545: pstmt.close();
0546:
0547: // Add the last known room subject to the room history only for those rooms that still
0548: // don't have in their histories the last room subject
0549: for (MUCRoom loadedRoom : rooms.values()) {
0550: if (!loadedRoom.getRoomHistory().hasChangedSubject()
0551: && loadedRoom.getSubject() != null
0552: && loadedRoom.getSubject().length() > 0) {
0553: loadedRoom.getRoomHistory().addOldMessage(
0554: loadedRoom.getRole().getRoleAddress()
0555: .toString(), null,
0556: loadedRoom.getModificationDate(),
0557: loadedRoom.getSubject(), null);
0558: }
0559: }
0560:
0561: pstmt = con.prepareStatement(LOAD_ALL_AFFILIATIONS);
0562: rs = pstmt.executeQuery();
0563: while (rs.next()) {
0564: long roomID = rs.getLong(1);
0565: String jid = rs.getString(2);
0566: MUCRole.Affiliation affiliation = MUCRole.Affiliation
0567: .valueOf(rs.getInt(3));
0568: room = (LocalMUCRoom) rooms.get(roomID);
0569: // Skip to the next position if the room does not exist
0570: if (room == null) {
0571: continue;
0572: }
0573: try {
0574: switch (affiliation) {
0575: case owner:
0576: room.addOwner(jid, room.getRole());
0577: break;
0578: case admin:
0579: room.addAdmin(jid, room.getRole());
0580: break;
0581: case outcast:
0582: room.addOutcast(jid, null, room.getRole());
0583: break;
0584: default:
0585: Log
0586: .error("Unkown affiliation value "
0587: + affiliation + " for user "
0588: + jid + " in persistent room "
0589: + room.getID());
0590: }
0591: } catch (Exception e) {
0592: Log.error(e);
0593: }
0594: }
0595: rs.close();
0596: pstmt.close();
0597:
0598: pstmt = con.prepareStatement(LOAD_ALL_MEMBERS);
0599: rs = pstmt.executeQuery();
0600: while (rs.next()) {
0601: room = (LocalMUCRoom) rooms.get(rs.getLong(1));
0602: // Skip to the next position if the room does not exist
0603: if (room == null) {
0604: continue;
0605: }
0606: try {
0607: room.addMember(rs.getString(2), rs.getString(3),
0608: room.getRole());
0609: } catch (Exception e) {
0610: Log.error(e);
0611: }
0612: }
0613: rs.close();
0614: } catch (SQLException sqle) {
0615: Log.error(sqle);
0616: } finally {
0617: try {
0618: if (pstmt != null)
0619: pstmt.close();
0620: } catch (Exception e) {
0621: Log.error(e);
0622: }
0623: try {
0624: if (con != null)
0625: con.close();
0626: } catch (Exception e) {
0627: Log.error(e);
0628: }
0629: }
0630: // Set now that the room's configuration is updated in the database. Note: We need to
0631: // set this now since otherwise the room's affiliations will be saved to the database
0632: // "again" while adding them to the room!
0633: for (MUCRoom room : rooms.values()) {
0634: room.setSavedToDB(true);
0635: if (room.getEmptyDate() == null) {
0636: // The service process was killed somehow while the room was being used. Since
0637: // the room won't have occupants at this time we need to set the best date when
0638: // the last occupant left the room that we can
0639: room.setEmptyDate(new Date());
0640: }
0641: }
0642:
0643: return rooms.values();
0644: }
0645:
0646: /**
0647: * Updates the room's subject in the database.
0648: *
0649: * @param room the room to update its subject in the database.
0650: */
0651: public static void updateRoomSubject(MUCRoom room) {
0652: if (!room.isPersistent() || !room.wasSavedToDB()) {
0653: return;
0654: }
0655:
0656: Connection con = null;
0657: PreparedStatement pstmt = null;
0658: try {
0659: con = DbConnectionManager.getConnection();
0660: pstmt = con.prepareStatement(UPDATE_SUBJECT);
0661: pstmt.setString(1, room.getSubject());
0662: pstmt.setLong(2, room.getID());
0663: pstmt.executeUpdate();
0664: } catch (SQLException sqle) {
0665: Log.error(sqle);
0666: } finally {
0667: try {
0668: if (pstmt != null)
0669: pstmt.close();
0670: } catch (Exception e) {
0671: Log.error(e);
0672: }
0673: try {
0674: if (con != null)
0675: con.close();
0676: } catch (Exception e) {
0677: Log.error(e);
0678: }
0679: }
0680: }
0681:
0682: /**
0683: * Updates the room's lock status in the database.
0684: *
0685: * @param room the room to update its lock status in the database.
0686: */
0687: public static void updateRoomLock(LocalMUCRoom room) {
0688: if (!room.isPersistent() || !room.wasSavedToDB()) {
0689: return;
0690: }
0691:
0692: Connection con = null;
0693: PreparedStatement pstmt = null;
0694: try {
0695: con = DbConnectionManager.getConnection();
0696: pstmt = con.prepareStatement(UPDATE_LOCK);
0697: pstmt.setString(1, StringUtils.dateToMillis(room
0698: .getLockedDate()));
0699: pstmt.setLong(2, room.getID());
0700: pstmt.executeUpdate();
0701: } catch (SQLException sqle) {
0702: Log.error(sqle);
0703: } finally {
0704: try {
0705: if (pstmt != null)
0706: pstmt.close();
0707: } catch (Exception e) {
0708: Log.error(e);
0709: }
0710: try {
0711: if (con != null)
0712: con.close();
0713: } catch (Exception e) {
0714: Log.error(e);
0715: }
0716: }
0717: }
0718:
0719: /**
0720: * Updates the room's lock status in the database.
0721: *
0722: * @param room the room to update its lock status in the database.
0723: */
0724: public static void updateRoomEmptyDate(MUCRoom room) {
0725: if (!room.isPersistent() || !room.wasSavedToDB()) {
0726: return;
0727: }
0728:
0729: Connection con = null;
0730: PreparedStatement pstmt = null;
0731: try {
0732: con = DbConnectionManager.getConnection();
0733: pstmt = con.prepareStatement(UPDATE_EMPTYDATE);
0734: Date emptyDate = room.getEmptyDate();
0735: if (emptyDate == null) {
0736: pstmt.setString(1, null);
0737: } else {
0738: pstmt.setString(1, StringUtils.dateToMillis(emptyDate));
0739: }
0740: pstmt.setLong(2, room.getID());
0741: pstmt.executeUpdate();
0742: } catch (SQLException sqle) {
0743: Log.error(sqle);
0744: } finally {
0745: try {
0746: if (pstmt != null)
0747: pstmt.close();
0748: } catch (Exception e) {
0749: Log.error(e);
0750: }
0751: try {
0752: if (con != null)
0753: con.close();
0754: } catch (Exception e) {
0755: Log.error(e);
0756: }
0757: }
0758: }
0759:
0760: /**
0761: * Update the DB with the new affiliation of the user in the room. The new information will be
0762: * saved only if the room is_persistent and has already been saved to the database previously.
0763: *
0764: * @param room The room where the affiliation of the user was updated.
0765: * @param bareJID The bareJID of the user to update this affiliation.
0766: * @param nickname The reserved nickname of the user in the room or null if none.
0767: * @param newAffiliation the new affiliation of the user in the room.
0768: * @param oldAffiliation the previous affiliation of the user in the room.
0769: */
0770: public static void saveAffiliationToDB(MUCRoom room,
0771: String bareJID, String nickname,
0772: MUCRole.Affiliation newAffiliation,
0773: MUCRole.Affiliation oldAffiliation) {
0774: if (!room.isPersistent() || !room.wasSavedToDB()) {
0775: return;
0776: }
0777: if (MUCRole.Affiliation.none == oldAffiliation) {
0778: if (MUCRole.Affiliation.member == newAffiliation) {
0779: // Add the user to the members table
0780: Connection con = null;
0781: PreparedStatement pstmt = null;
0782: try {
0783: con = DbConnectionManager.getConnection();
0784: pstmt = con.prepareStatement(ADD_MEMBER);
0785: pstmt.setLong(1, room.getID());
0786: pstmt.setString(2, bareJID);
0787: pstmt.setString(3, nickname);
0788: pstmt.executeUpdate();
0789: } catch (SQLException sqle) {
0790: Log.error(sqle);
0791: } finally {
0792: try {
0793: if (pstmt != null)
0794: pstmt.close();
0795: } catch (Exception e) {
0796: Log.error(e);
0797: }
0798: try {
0799: if (con != null)
0800: con.close();
0801: } catch (Exception e) {
0802: Log.error(e);
0803: }
0804: }
0805: } else {
0806: // Add the user to the generic affiliations table
0807: Connection con = null;
0808: PreparedStatement pstmt = null;
0809: try {
0810: con = DbConnectionManager.getConnection();
0811: pstmt = con.prepareStatement(ADD_AFFILIATION);
0812: pstmt.setLong(1, room.getID());
0813: pstmt.setString(2, bareJID);
0814: pstmt.setInt(3, newAffiliation.getValue());
0815: pstmt.executeUpdate();
0816: } catch (SQLException sqle) {
0817: Log.error(sqle);
0818: } finally {
0819: try {
0820: if (pstmt != null)
0821: pstmt.close();
0822: } catch (Exception e) {
0823: Log.error(e);
0824: }
0825: try {
0826: if (con != null)
0827: con.close();
0828: } catch (Exception e) {
0829: Log.error(e);
0830: }
0831: }
0832: }
0833: } else {
0834: if (MUCRole.Affiliation.member == newAffiliation
0835: && MUCRole.Affiliation.member == oldAffiliation) {
0836: // Update the member's data in the member table.
0837: Connection con = null;
0838: PreparedStatement pstmt = null;
0839: try {
0840: con = DbConnectionManager.getConnection();
0841: pstmt = con.prepareStatement(UPDATE_MEMBER);
0842: pstmt.setString(1, nickname);
0843: pstmt.setLong(2, room.getID());
0844: pstmt.setString(3, bareJID);
0845: pstmt.executeUpdate();
0846: } catch (SQLException sqle) {
0847: Log.error(sqle);
0848: } finally {
0849: try {
0850: if (pstmt != null)
0851: pstmt.close();
0852: } catch (Exception e) {
0853: Log.error(e);
0854: }
0855: try {
0856: if (con != null)
0857: con.close();
0858: } catch (Exception e) {
0859: Log.error(e);
0860: }
0861: }
0862: } else if (MUCRole.Affiliation.member == newAffiliation) {
0863: Connection con = null;
0864: PreparedStatement pstmt = null;
0865: boolean abortTransaction = false;
0866: try {
0867: // Remove the user from the generic affiliations table
0868: con = DbConnectionManager
0869: .getTransactionConnection();
0870: pstmt = con.prepareStatement(DELETE_AFFILIATION);
0871: pstmt.setLong(1, room.getID());
0872: pstmt.setString(2, bareJID);
0873: pstmt.executeUpdate();
0874: pstmt.close();
0875:
0876: // Add them as a member.
0877: pstmt = con.prepareStatement(ADD_MEMBER);
0878: pstmt.setLong(1, room.getID());
0879: pstmt.setString(2, bareJID);
0880: pstmt.setString(3, nickname);
0881: pstmt.executeUpdate();
0882: } catch (SQLException sqle) {
0883: Log.error(sqle);
0884: abortTransaction = true;
0885: } finally {
0886: try {
0887: if (pstmt != null)
0888: pstmt.close();
0889: } catch (Exception e) {
0890: Log.error(e);
0891: }
0892: DbConnectionManager.closeTransactionConnection(con,
0893: abortTransaction);
0894: }
0895: } else if (MUCRole.Affiliation.member == oldAffiliation) {
0896: Connection con = null;
0897: PreparedStatement pstmt = null;
0898: boolean abortTransaction = false;
0899: try {
0900: con = DbConnectionManager
0901: .getTransactionConnection();
0902: pstmt = con.prepareStatement(DELETE_MEMBER);
0903: pstmt.setLong(1, room.getID());
0904: pstmt.setString(2, bareJID);
0905: pstmt.executeUpdate();
0906: pstmt.close();
0907:
0908: pstmt = con.prepareStatement(ADD_AFFILIATION);
0909: pstmt.setLong(1, room.getID());
0910: pstmt.setString(2, bareJID);
0911: pstmt.setInt(3, newAffiliation.getValue());
0912: pstmt.executeUpdate();
0913: } catch (SQLException sqle) {
0914: Log.error(sqle);
0915: abortTransaction = true;
0916: } finally {
0917: try {
0918: if (pstmt != null)
0919: pstmt.close();
0920: } catch (Exception e) {
0921: Log.error(e);
0922: }
0923: DbConnectionManager.closeTransactionConnection(con,
0924: abortTransaction);
0925: }
0926: } else {
0927: // Update the user in the generic affiliations table.
0928: Connection con = null;
0929: PreparedStatement pstmt = null;
0930: try {
0931: con = DbConnectionManager.getConnection();
0932: pstmt = con.prepareStatement(UPDATE_AFFILIATION);
0933: pstmt.setInt(1, newAffiliation.getValue());
0934: pstmt.setLong(2, room.getID());
0935: pstmt.setString(3, bareJID);
0936: pstmt.executeUpdate();
0937: } catch (SQLException sqle) {
0938: Log.error(sqle);
0939: } finally {
0940: try {
0941: if (pstmt != null)
0942: pstmt.close();
0943: } catch (Exception e) {
0944: Log.error(e);
0945: }
0946: try {
0947: if (con != null)
0948: con.close();
0949: } catch (Exception e) {
0950: Log.error(e);
0951: }
0952: }
0953: }
0954: }
0955: }
0956:
0957: /**
0958: * Removes the affiliation of the user from the DB if the room is persistent.
0959: *
0960: * @param room The room where the affiliation of the user was removed.
0961: * @param bareJID The bareJID of the user to remove his affiliation.
0962: * @param oldAffiliation the previous affiliation of the user in the room.
0963: */
0964: public static void removeAffiliationFromDB(MUCRoom room,
0965: String bareJID, MUCRole.Affiliation oldAffiliation) {
0966: if (room.isPersistent() && room.wasSavedToDB()) {
0967: if (MUCRole.Affiliation.member == oldAffiliation) {
0968: // Remove the user from the members table
0969: Connection con = null;
0970: PreparedStatement pstmt = null;
0971: try {
0972: con = DbConnectionManager.getConnection();
0973: pstmt = con.prepareStatement(DELETE_MEMBER);
0974: pstmt.setLong(1, room.getID());
0975: pstmt.setString(2, bareJID);
0976: pstmt.executeUpdate();
0977: } catch (SQLException sqle) {
0978: Log.error(sqle);
0979: } finally {
0980: try {
0981: if (pstmt != null)
0982: pstmt.close();
0983: } catch (Exception e) {
0984: Log.error(e);
0985: }
0986: try {
0987: if (con != null)
0988: con.close();
0989: } catch (Exception e) {
0990: Log.error(e);
0991: }
0992: }
0993: } else {
0994: // Remove the user from the generic affiliations table
0995: Connection con = null;
0996: PreparedStatement pstmt = null;
0997: try {
0998: con = DbConnectionManager.getConnection();
0999: pstmt = con.prepareStatement(DELETE_AFFILIATION);
1000: pstmt.setLong(1, room.getID());
1001: pstmt.setString(2, bareJID);
1002: pstmt.executeUpdate();
1003: } catch (SQLException sqle) {
1004: Log.error(sqle);
1005: } finally {
1006: try {
1007: if (pstmt != null)
1008: pstmt.close();
1009: } catch (Exception e) {
1010: Log.error(e);
1011: }
1012: try {
1013: if (con != null)
1014: con.close();
1015: } catch (Exception e) {
1016: Log.error(e);
1017: }
1018: }
1019: }
1020: }
1021: }
1022:
1023: /**
1024: * Saves the conversation log entry to the database.
1025: *
1026: * @param entry the ConversationLogEntry to save to the database.
1027: * @return true if the ConversationLogEntry was saved successfully to the database.
1028: */
1029: public static boolean saveConversationLogEntry(
1030: ConversationLogEntry entry) {
1031: Connection con = null;
1032: PreparedStatement pstmt = null;
1033: try {
1034: con = DbConnectionManager.getConnection();
1035: pstmt = con.prepareStatement(ADD_CONVERSATION_LOG);
1036: pstmt.setLong(1, entry.getRoomID());
1037: pstmt.setString(2, entry.getSender().toString());
1038: pstmt.setString(3, entry.getNickname());
1039: pstmt.setString(4, StringUtils
1040: .dateToMillis(entry.getDate()));
1041: pstmt.setString(5, entry.getSubject());
1042: pstmt.setString(6, entry.getBody());
1043: pstmt.executeUpdate();
1044: return true;
1045: } catch (SQLException sqle) {
1046: Log.error("Error saving conversation log entry", sqle);
1047: return false;
1048: } finally {
1049: try {
1050: if (pstmt != null)
1051: pstmt.close();
1052: } catch (Exception e) {
1053: Log.error(e);
1054: }
1055: try {
1056: if (con != null)
1057: con.close();
1058: } catch (Exception e) {
1059: Log.error(e);
1060: }
1061: }
1062: }
1063:
1064: /**
1065: * Returns an integer based on the binary representation of the roles to broadcast.
1066: *
1067: * @param room the room to marshall its roles to broadcast.
1068: * @return an integer based on the binary representation of the roles to broadcast.
1069: */
1070: private static int marshallRolesToBroadcast(MUCRoom room) {
1071: StringBuilder buffer = new StringBuilder();
1072: buffer.append((room.canBroadcastPresence("moderator") ? "1"
1073: : "0"));
1074: buffer.append((room.canBroadcastPresence("participant") ? "1"
1075: : "0"));
1076: buffer
1077: .append((room.canBroadcastPresence("visitor") ? "1"
1078: : "0"));
1079: return Integer.parseInt(buffer.toString(), 2);
1080: }
1081: }
|