/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev$
* Last modified by $Author$
* $Date$
*/
package tigase.xmpp.impl.xep0136;
//~--- non-JDK imports --------------------------------------------------------
import tigase.db.DataRepository;
import tigase.db.RepositoryFactory;
import tigase.server.Packet;
import tigase.util.SimpleCache;
import tigase.xmpp.BareJID;
//~--- JDK imports ------------------------------------------------------------
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
//~--- classes ----------------------------------------------------------------
/**
* Describe class MessageArchiveDB here.
*
*
* Created: Fri Feb 29 22:34:29 2008
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public class MessageArchiveDB {
/**
* Variable <code>log</code> is a class logger.
*/
private static final Logger log = Logger.getLogger(MessageArchiveDB.class.getName());
private static final long LONG_NULL = 0;
private static final String ADD_JID_QUERY = "insert into tig_ma_jid (jid) values (?)";
private static final String GET_JID_ID_QUERY = "select ma_j_id from tig_ma_jid where jid = ?";
private static final String GET_JID_IDS_QUERY =
"select * from tig_ma_jid where (jid = ?) or (jid = ?)";
private static final String ADD_THREAD_QUERY = "insert into tig_ma_thread (thread) values (?)";
private static final String GET_THREAD_ID_QUERY =
"select ma_t_id from tig_ma_thread where (thread = ?)";
private static final String ADD_SUBJECT_QUERY = "insert into tig_ma_subject (subject) values (?)";
private static final String GET_SUBJECT_ID_QUERY =
"select ma_s_id from tig_ma_subject where (subject = ?)";
//~--- fields ---------------------------------------------------------------
private Map<String, Object> cache = null;
//private PreparedStatement save_message_st = null;
//private PreparedStatement get_msg_for_jid_st = null;
//private PreparedStatement get_jid_id_st = null;
//private PreparedStatement get_jids_id_st = null;
//private PreparedStatement add_jid_st = null;
//private PreparedStatement add_thread_st = null;
//private PreparedStatement get_thread_id_st = null;
//private PreparedStatement add_subject_st = null;
//private PreparedStatement get_subject_id_st = null;
private int cacheSize = 10000;
private long cacheTime = 60 * 60 * 1000;
private DataRepository data_repo = null;
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param jid
* @param with_jid
* @param timestamp
* @param limit
*/
public void getMessages(String jid, String with_jid, Date timestamp, int limit) {}
//~--- methods --------------------------------------------------------------
/**
* <code>initRepository</code> method is doing lazy initialization with database.
* Connection to database will be established during the first authentication
* request.
*
* @param conn_str a <code>String</code> value of database connection string.
* The string must also contain database user name and password if required
* for connection.
* @param params
* @exception SQLException if an error occurs during access database. It won't
* happen however as in this method we do simple variable assigment.
*/
public void initRepository(String conn_str, Map<String, String> params) throws SQLException {
try {
data_repo = RepositoryFactory.getDataRepository(null, conn_str, params);
data_repo.initPreparedStatement(ADD_JID_QUERY, ADD_JID_QUERY);
data_repo.initPreparedStatement(GET_JID_ID_QUERY, GET_JID_ID_QUERY);
data_repo.initPreparedStatement(GET_JID_IDS_QUERY, GET_JID_IDS_QUERY);
data_repo.initPreparedStatement(ADD_THREAD_QUERY, ADD_THREAD_QUERY);
data_repo.initPreparedStatement(GET_THREAD_ID_QUERY, GET_THREAD_ID_QUERY);
data_repo.initPreparedStatement(ADD_SUBJECT_QUERY, ADD_SUBJECT_QUERY);
data_repo.initPreparedStatement(GET_SUBJECT_ID_QUERY, GET_SUBJECT_ID_QUERY);
} catch (Exception ex) {}
cache = Collections.synchronizedMap(new SimpleCache<String, Object>(10000, 60 * 1000));
}
/**
* Method description
*
*
* @param message
* @param full_content
* @param defLang
*
* @throws SQLException
*/
public void saveMessage(Packet message, boolean full_content, String defLang)
throws SQLException {
BareJID from_str = message.getStanzaFrom().getBareJID();
BareJID to_str = message.getStanzaTo().getBareJID();
long[] ids = getJidsIds(from_str.toString(), to_str.toString());
long from_id = ((ids[0] != LONG_NULL) ? ids[0] : addJidID(from_str.toString()));
long to_id = ((ids[1] != LONG_NULL) ? ids[1] : addJidID(to_str.toString()));
String thread = message.getElemCData("/message/thread");
long thread_id = LONG_NULL;
String subject = message.getElemCData("/message/subject");
long subject_id = LONG_NULL;
if ((thread != null) &&!thread.trim().isEmpty()) {
thread_id = addThreadID(thread);
}
if ((subject != null) &&!subject.trim().isEmpty()) {
subject_id = addSubjectID(subject);
}
}
private long addJidID(String jid) throws SQLException {
PreparedStatement add_jid_st = data_repo.getPreparedStatement(null, ADD_JID_QUERY);
synchronized (add_jid_st) {
add_jid_st.setString(1, jid);
add_jid_st.executeUpdate();
}
// This is not the most effective solution but this method shouldn't be
// called very often so the perfrmance impact should be insignificant.
long[] jid_ids = getJidsIds(jid);
if (jid_ids != null) {
return jid_ids[0];
} else {
// That should never happen here, but just in case....
log.log(Level.WARNING, "I have just added new jid but it was not found.... {0}", jid);
return LONG_NULL;
}
}
private long addSubjectID(String subject) throws SQLException {
long result = getSubjectID(subject);
if (result != LONG_NULL) {
return result;
}
PreparedStatement add_subject_st = data_repo.getPreparedStatement(null, ADD_SUBJECT_QUERY);
synchronized (add_subject_st) {
add_subject_st.setString(1, subject);
add_subject_st.executeUpdate();
}
// This is not the most effective solution but this method shouldn't be
// called very often so the perfrmance impact should be insignificant.
result = getSubjectID(subject);
return result;
}
private long addThreadID(String thread) throws SQLException {
long result = getThreadID(thread);
if (result != LONG_NULL) {
return result;
}
PreparedStatement add_thread_st = data_repo.getPreparedStatement(null, ADD_THREAD_QUERY);
synchronized (add_thread_st) {
add_thread_st.setString(1, thread);
add_thread_st.executeUpdate();
}
// This is not the most effective solution but this method shouldn't be
// called very often so the perfrmance impact should be insignificant.
result = getThreadID(thread);
return result;
}
//~--- get methods ----------------------------------------------------------
private long[] getJidsIds(String... jids) throws SQLException {
ResultSet rs = null;
try {
long[] results = new long[jids.length];
for (int i = 0; i < results.length; i++) {
results[i] = LONG_NULL;
}
if (jids.length == 1) {
PreparedStatement get_jid_id_st = data_repo.getPreparedStatement(null, GET_JID_ID_QUERY);
synchronized (get_jid_id_st) {
get_jid_id_st.setString(1, jids[0]);
rs = get_jid_id_st.executeQuery();
if (rs.next()) {
results[0] = rs.getLong("ma_j_id");
return results;
}
}
return null;
} else {
PreparedStatement get_jids_id_st = data_repo.getPreparedStatement(null, GET_JID_IDS_QUERY);
synchronized (get_jids_id_st) {
for (int i = 0; i < jids.length; i++) {
get_jids_id_st.setString(i + 1, jids[i]);
}
rs = get_jids_id_st.executeQuery();
int cnt = 0;
while (rs.next()) {
String db_jid = rs.getString("jid");
for (int i = 0; i < jids.length; i++) {
if (db_jid.equals(jids[i])) {
results[i] = rs.getLong("ma_j_id");
++cnt;
}
}
}
if (cnt > 0) {
return results;
} else {
return null;
}
}
}
} finally {
data_repo.release(null, rs);
}
// return results;
}
private long getSubjectID(String subject) throws SQLException {
ResultSet rs = null;
try {
PreparedStatement get_subject_id_st = data_repo.getPreparedStatement(null, GET_SUBJECT_ID_QUERY);
synchronized (get_subject_id_st) {
get_subject_id_st.setString(1, subject);
rs = get_subject_id_st.executeQuery();
if (rs.next()) {
return rs.getLong("ma_s_id");
}
}
} finally {
data_repo.release(null, rs);
}
return LONG_NULL;
}
private long getThreadID(String thread) throws SQLException {
ResultSet rs = null;
try {
PreparedStatement get_thread_id_st = data_repo.getPreparedStatement(null, GET_THREAD_ID_QUERY);
synchronized (get_thread_id_st) {
get_thread_id_st.setString(1, thread);
rs = get_thread_id_st.executeQuery();
if (rs.next()) {
return rs.getLong("ma_t_id");
}
}
} finally {
data_repo.release(null, rs);
}
return LONG_NULL;
}
}
//~ Formatted in Sun Code Convention
//~ Formatted by Jindent --- http://www.jindent.com