/*
* 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.server.xmppclient;
//~--- non-JDK imports --------------------------------------------------------
import tigase.util.TigaseStringprepException;
import tigase.xmpp.BareJID;
import tigase.db.DBInitException;
import tigase.db.DataRepository;
import tigase.db.RepositoryFactory;
import tigase.db.UserNotFoundException;
//~--- JDK imports ------------------------------------------------------------
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.logging.Level;
import java.util.logging.Logger;
//~--- classes ----------------------------------------------------------------
/**
* Extended implementation of SeeOtherHost using redirect information from
* database
*
*/
public class SeeOtherHostDB extends SeeOtherHostHashed {
private static final Logger log = Logger.getLogger(SeeOtherHostDB.class.getName());
public static final String SEE_OTHER_HOST_TABLE = "tig_see_other_hosts";
public static final String SEE_OTHER_HOST_DB_URL_KEY = CM_SEE_OTHER_HOST_CLASS_PROP_KEY
+ "/" + "db-url";
public static final String SEE_OTHER_HOST_DB_QUERY_KEY =
CM_SEE_OTHER_HOST_CLASS_PROP_KEY + "/" + "get-host-query";
public static final String DB_GET_ALL_DATA_DB_QUERY_KEY =
CM_SEE_OTHER_HOST_CLASS_PROP_KEY + "/" + "get-all-data-query";
public static final String GET_ALL_QUERY_TIMEOUT_QUERY_KEY =
CM_SEE_OTHER_HOST_CLASS_PROP_KEY + "/" + "get-all-query-timeout";
public static final String SERIAL_ID = "sid";
public static final String USER_ID = "uid";
public static final String NODE_ID = "node_id";
public static final String DEF_DB_GET_HOST_QUERY = " select * from tig_users, "
+ SEE_OTHER_HOST_TABLE + " where tig_users.uid = " + SEE_OTHER_HOST_TABLE + "."
+ USER_ID + " and user_id = ?";
private static final String DEF_DB_GET_ALL_DATA_QUERY =
"select user_id, node_id from tig_users, " + SEE_OTHER_HOST_TABLE
+ " where tig_users.uid = " + SEE_OTHER_HOST_TABLE + "." + USER_ID;
private static final String CREATE_STATS_TABLE = "create table " + SEE_OTHER_HOST_TABLE
+ " ( " + SERIAL_ID + " serial," + USER_ID + " bigint unsigned NOT NULL, "
+ NODE_ID + " varchar(2049) NOT NULL, " + " primary key (" + SERIAL_ID + "), "
+ " constraint tig_see_other_host_constr foreign key (" + USER_ID
+ ") references tig_users (" + USER_ID + ")" + ")";
private static final int DEF_QUERY_TIME_OUT = 0;
private String get_host_query = DEF_DB_GET_HOST_QUERY;
private String get_all_data_query = DEF_DB_GET_ALL_DATA_QUERY;
private String get_host_DB_url = "";
private DataRepository data_repo = null;
private Map<BareJID, BareJID> redirectsMap =
new ConcurrentSkipListMap<BareJID, BareJID>();
// Methods
@Override
public BareJID findHostForJID(BareJID jid, BareJID host) {
BareJID see_other_host = redirectsMap.get(jid);
if (see_other_host != null) {
return see_other_host;
} else {
see_other_host = host;
}
try {
see_other_host = queryDB(jid);
} catch (Exception ex) {
see_other_host = super.findHostForJID(jid, host);
log.log(Level.SEVERE, "DB lookup failed, fallback to SeeOtherHostHashed: ", ex);
}
return see_other_host;
}
@Override
public void getDefaults(Map<String, Object> defs, Map<String, Object> params) {
super.getDefaults(defs, params);
if (params.containsKey("--user-db-uri")) {
get_host_DB_url = (String) params.get("--user-db-uri");
}
defs.put(SEE_OTHER_HOST_DB_URL_KEY, get_host_DB_url);
defs.put(SEE_OTHER_HOST_DB_QUERY_KEY, get_host_query);
defs.put(DB_GET_ALL_DATA_DB_QUERY_KEY, get_all_data_query);
}
@Override
public void setProperties(Map<String, Object> props) {
super.setProperties(props);
if ((props.containsKey(SEE_OTHER_HOST_DB_URL_KEY))
&& !props.get(SEE_OTHER_HOST_DB_URL_KEY).toString().trim().isEmpty()) {
get_host_DB_url = props.get(SEE_OTHER_HOST_DB_URL_KEY).toString().trim();
}
props.put(SEE_OTHER_HOST_DB_URL_KEY, get_host_DB_url);
if ((props.containsKey(SEE_OTHER_HOST_DB_QUERY_KEY))
&& !props.get(SEE_OTHER_HOST_DB_QUERY_KEY).toString().trim().isEmpty()) {
get_host_query = props.get(SEE_OTHER_HOST_DB_QUERY_KEY).toString().trim();
}
props.put(SEE_OTHER_HOST_DB_QUERY_KEY, get_host_query);
if ((props.containsKey(DB_GET_ALL_DATA_DB_QUERY_KEY))
&& !props.get(DB_GET_ALL_DATA_DB_QUERY_KEY).toString().trim().isEmpty()) {
get_all_data_query = props.get(DB_GET_ALL_DATA_DB_QUERY_KEY).toString().trim();
}
props.put(DB_GET_ALL_DATA_DB_QUERY_KEY, get_all_data_query);
try {
initRepository(get_host_DB_url, null);
} catch (Exception ex) {
log.log(Level.SEVERE, "Cannot initialize connection to database: ", ex);
}
}
public void initRepository(String conn_str, Map<String, String> map)
throws SQLException, ClassNotFoundException, IllegalAccessException,
InstantiationException, DBInitException {
log.log(Level.INFO, "Initializing dbAccess for db connection url: {0}", conn_str);
data_repo = RepositoryFactory.getDataRepository(null, conn_str, map);
// checkDB();
data_repo.initPreparedStatement(get_host_query, get_host_query);
data_repo.initPreparedStatement(get_all_data_query, get_all_data_query);
queryAllDB();
}
// private void checkDB() throws SQLException {
// data_repo.checkTable(SEE_OTHER_HOST_TABLE, CREATE_STATS_TABLE);
// }
private BareJID queryDB(BareJID user) throws UserNotFoundException, SQLException,
TigaseStringprepException {
PreparedStatement get_host = data_repo.getPreparedStatement(user, get_host_query);
ResultSet rs = null;
synchronized (get_host) {
get_host.setString(1, user.toString());
rs = get_host.executeQuery();
if (rs.next()) {
return BareJID.bareJIDInstance(rs.getString(NODE_ID));
} else {
throw new UserNotFoundException("Item does not exist for user: " + user);
} // end of if (isnext) else
}
}
private void queryAllDB() throws SQLException {
PreparedStatement get_all = data_repo.getPreparedStatement(null, get_all_data_query);
get_all.setQueryTimeout(DEF_QUERY_TIME_OUT);
ResultSet rs = null;
synchronized (get_all) {
rs = get_all.executeQuery();
while (rs.next()) {
String user_jid = rs.getString("user_id");
String node_jid = rs.getString(NODE_ID);;
try {
BareJID user = BareJID.bareJIDInstance(user_jid);
BareJID node = BareJID.bareJIDInstance(node_jid);
redirectsMap.put(user, node);
} catch (TigaseStringprepException ex) {
log.warning("Invalid user's or node's JID: " + user_jid + ", " + node_jid);
}
} // end of if (isnext) else
}
log.info("Loaded " + redirectsMap.size() + " redirect definitions from database.");
}
}