Package tigase.db.jdbc

Source Code of tigase.db.jdbc.JDBCRepository$RepoCache

/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2007 "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 General Public License as published by
* the Free Software Foundation, either 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev: 1250 $
* Last modified by $Author: kobit $
* $Date: 2008-12-01 13:32:35 +0000 (Mon, 01 Dec 2008) $
*/
package tigase.db.jdbc;


import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import tigase.db.AuthorizationException;
import tigase.db.DBInitException;
import tigase.db.RepositoryFactory;
import tigase.db.TigaseDBException;
import tigase.db.UserAuthRepository;
import tigase.db.UserAuthRepositoryImpl;
import tigase.db.UserExistsException;
import tigase.db.UserNotFoundException;
import tigase.db.UserRepository;
import tigase.util.SimpleCache;

/**
* Not synchronized implementation!
* Musn't be used by more than one thread at the same time.
* <p>
* Thanks to Daniele for better unique IDs handling.
* Created: Thu Oct 26 11:48:53 2006
* </p>
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @author <a href="mailto:piras@tiscali.com">Daniele</a>
* @version $Rev: 1250 $
*/
public class JDBCRepository implements UserAuthRepository, UserRepository {

  private static final Logger log =
    Logger.getLogger("tigase.db.jdbc.JDBCRepository");

  public static final String DEF_USERS_TBL = "tig_users";
  public static final String DEF_NODES_TBL = "tig_nodes";
  public static final String DEF_PAIRS_TBL = "tig_pairs";
  public static final String DEF_MAXIDS_TBL = "tig_max_ids";
  public static final String DEF_ROOT_NODE = "root";

  private static final String USER_STR = "User: ";

  public static final String DERBY_CONNVALID_QUERY = "values 1";
  public static final String JDBC_CONNVALID_QUERY = "select 1";

  public static final String DERBY_GETSCHEMAVER_QUERY
    = "values TigGetDBProperty('schema-version')";
  public static final String JDBC_GETSCHEMAVER_QUERY
    = "select TigGetDBProperty('schema-version')";

  //  private String users_tbl = DEF_USERS_TBL;
  private String nodes_tbl = DEF_NODES_TBL;
  private String pairs_tbl = DEF_PAIRS_TBL;
  //  private String maxids_tbl = DEF_MAXIDS_TBL;
  private String root_node = DEF_ROOT_NODE;

  private UserAuthRepository auth = null;
  private String db_conn = null;
  private Connection conn = null;
  private CallableStatement uid_sp = null;
  private CallableStatement users_count_sp = null;
  private CallableStatement all_users_sp = null;
  private CallableStatement user_add_sp = null;
  private CallableStatement user_del_sp = null;
  private CallableStatement node_add_sp = null;

  private PreparedStatement data_for_node_st = null;
  private PreparedStatement keys_for_node_st = null;
  private PreparedStatement nodes_for_node_st = null;
  private PreparedStatement insert_key_val_st = null;
  private PreparedStatement remove_key_data_st = null;
  private PreparedStatement conn_valid_st = null;

  private Map<String, Object> cache = null;

  private long lastConnectionValidated = 0;
  private long connectionValidateInterval = 1000*60;

  private boolean autoCreateUser = false;
  private boolean derby_mode = false;

//   private static long var_max_uid = 0;
//   private static long var_max_nid = 0;

//   /**
//    * Describe <code>getMaxUid</code> method handles unique IDs much better for
//    * distributed environment than the old code.
//    * Thank's to Daniele for the help and the code.
//    *
//    * @return a <code>long</code> value
//    */
//   private long getMaxUid() {
//     return (System.currentTimeMillis() * 100) + ((var_max_uid++) % 100);
//   }

//   /**
//    * <code>getMaxNid</code> method handles unique IDs much better for
//    * distributed environment than the old code.
//    * Thank's to Daniele for the help and the code.
//    *
//    * @return a <code>long</code> value
//    */
//   private long getMaxNid() {
//     return (System.currentTimeMillis() * 100) + ((var_max_nid++) % 100);
//   }

  private void release(Statement stmt, ResultSet rs) {
    if (rs != null) {
      try {
        rs.close();
      } catch (SQLException sqlEx) { }
    }
    if (stmt != null) {
      try {
        stmt.close();
      } catch (SQLException sqlEx) { }
    }
  }

  private boolean checkConnection() throws SQLException {
    ResultSet rs = null;
    try {
      synchronized (conn_valid_st) {
        long tmp = System.currentTimeMillis();
        if ((tmp - lastConnectionValidated) >= connectionValidateInterval) {
          rs = conn_valid_st.executeQuery();
          lastConnectionValidated = tmp;
        } // end of if ()
      }
    } catch (Exception e) {
      initRepo();
    } finally {
      release(null, rs);
    } // end of try-catch
    return true;
  }

  private long getUserUID(String user_id, boolean autoCreate)
    throws SQLException, UserNotFoundException, TigaseDBException {
    Long cache_res = (Long)cache.get(user_id);
    if (cache_res != null) {
      return cache_res.longValue();
    } // end of if (result != null)
    ResultSet rs = null;
    long result = -1;
    try {
      synchronized (uid_sp) {
        uid_sp.setString(1, user_id);
        rs = uid_sp.executeQuery();
        if (rs.next()) {
          result = rs.getLong(1);
        } else {
          result = -1;
        }
        if (result <= 0) {
          if (autoCreate) {
            result = addUserRepo(user_id);
          } else {
            throw new UserNotFoundException("User does not exist: " + user_id);
          } // end of if (autoCreate) else
        } // end of if (isnext) else
      }
    } finally {
      release(null, rs);
    }
    cache.put(user_id, Long.valueOf(result));
    return result;
  }

  public boolean userExists(String user) {
    try {
      getUserUID(user, false);
      return true;
    } catch (Exception e) {
      return false;
    }
  }

//   private void incrementMaxUID() throws SQLException {
//     Statement stmt = null;
//     try {
//       stmt = conn.createStatement();
//       // Update max_uid to current value
//       stmt.executeUpdate("update " + maxids_tbl + " set max_uid=(max_uid+1);");
//     } finally {
//       release(stmt, null);
//       stmt = null;
//     }
//   }

//   private void incrementMaxNID() throws SQLException {
//     Statement stmt = null;
//     try {
//       stmt = conn.createStatement();
//       // Update max_uid to current value
//       stmt.executeUpdate("update " + maxids_tbl + " set max_nid=(max_nid+1);");
//     } finally {
//       release(stmt, null);
//       stmt = null;
//     }
//   }

  private String buildNodeQuery(long uid, String node_path) {
    String query =
      "select nid as nid1 from " + nodes_tbl
      + " where (uid = " + uid + ")"
      + " AND (parent_nid is null)"
      + " AND (node = '" + root_node + "')";
    if (node_path == null) {
      return query;
    } else {
      StringTokenizer strtok = new StringTokenizer(node_path, "/", false);
      int cnt = 1;
      String subquery = query;
      while (strtok.hasMoreTokens()) {
        String token = strtok.nextToken();
        ++cnt;
        subquery = "select nid as nid" + cnt + ", node as node" + cnt
          + " from " + nodes_tbl + ", (" + subquery + ") nodes" + (cnt-1)
          + " where (parent_nid = nid" + (cnt-1) + ")"
          + " AND (node = '" + token + "')";
      } // end of while (strtok.hasMoreTokens())
      return subquery;
    } // end of else
  }

  private long getNodeNID(long uid, String node_path)
    throws SQLException, TigaseDBException, UserNotFoundException {
    String query = buildNodeQuery(uid, node_path);
    log.finest(query);
    Statement stmt = null;
    ResultSet rs = null;
    long nid = -1;
    try {
      stmt = conn.createStatement();
      rs = stmt.executeQuery(query);
      if (rs.next()) {
        nid = rs.getLong(1);
      } else {
        nid = -1;
      } // end of if (isnext) else
      if (nid <= 0) {
        if (node_path == null) {
          log.warning("Missing root node, database upgrade or bug in the code? Adding missing root node now.");
          nid = addNode(uid, -1, "root");
        } else {
          log.finest("Missing nid for node path: "
            + node_path + " and uid: " + uid);
        }
      }
      return nid;
    } finally {
      release(stmt, rs);
      stmt = null; rs = null;
    }
  }

  private long getNodeNID(String user_id, String node_path)
    throws SQLException, UserNotFoundException, TigaseDBException {
    Long cache_res = (Long)cache.get(user_id+"/"+node_path);
    if (cache_res != null) {
      return cache_res.longValue();
    } // end of if (result != null)
    long uid = getUserUID(user_id, autoCreateUser);
    long result = getNodeNID(uid, node_path);
    if (result > 0) {
      cache.put(user_id+"/"+node_path, Long.valueOf(result));
    } // end of if (result > 0)
    return result;
  }

  private long addNode(long uid, long parent_nid, String node_name)
    throws SQLException, TigaseDBException {
    ResultSet rs = null;
    long new_nid = -1;
    synchronized (node_add_sp) {
      try {
        if (parent_nid < 0) {
          node_add_sp.setNull(1, Types.BIGINT);
        } else {
          node_add_sp.setLong(1, parent_nid);
        } // end of else
        node_add_sp.setLong(2, uid);
        node_add_sp.setString(3, node_name);
        //node_add_sp.registerOutParameter(4, Types.BIGINT);
        rs = node_add_sp.executeQuery();
        if (rs.next()) {
          return rs.getLong(1);
        } else {
          log.warning("Missing NID after adding new node...");
          throw new TigaseDBException("Propeblem adding new node. "
            + "The SP should return nid or fail");
        } // end of if (isnext) else
      } finally {
        release(null, rs);
      }
    }
    //return new_nid;
  }

  private long createNodePath(String user_id, String node_path)
    throws SQLException, UserNotFoundException, TigaseDBException {
    if (node_path == null) {
      // Or should I throw NullPointerException?
      return getNodeNID(user_id, null);
    } // end of if (node_path == null)
    long uid = getUserUID(user_id, autoCreateUser);
    long nid = getNodeNID(uid, null);
    StringTokenizer strtok = new StringTokenizer(node_path, "/", false);
    StringBuilder built_path = new StringBuilder();
    while (strtok.hasMoreTokens()) {
      String token = strtok.nextToken();
      built_path.append("/").append(token);
      long cur_nid = getNodeNID(uid, built_path.toString());
      if (cur_nid > 0) {
        nid = cur_nid;
      } else {
        nid = addNode(uid, nid, token);
      } // end of if (cur_nid > 0) else
    } // end of while (strtok.hasMoreTokens())
    return nid;
  }

  private void initPreparedStatements() throws SQLException {
    String query = "{ call TigGetUserDBUid(?) }";
    uid_sp = conn.prepareCall(query);

    query = "{ call TigAllUsersCount() }";
    users_count_sp = conn.prepareCall(query);

    query = "{ call TigAllUsers() }";
    all_users_sp = conn.prepareCall(query);

    query = "{ call TigAddUserPlainPw(?, ?) }";
    user_add_sp = conn.prepareCall(query);

    query = "{ call TigRemoveUser(?) }";
    user_del_sp = conn.prepareCall(query);


    query = "{ call TigAddNode(?, ?, ?) }";
    node_add_sp = conn.prepareCall(query);

    query = "select pval from " + pairs_tbl
      + " where (nid = ?) AND (pkey = ?)";
    data_for_node_st = conn.prepareStatement(query);

    query = "select pkey from " + pairs_tbl
      + " where (nid = ?)";
    keys_for_node_st = conn.prepareStatement(query);

    query = "select nid, node from " + nodes_tbl
      + " where parent_nid = ?";
    nodes_for_node_st = conn.prepareStatement(query);

    query =  "insert into " + pairs_tbl  + " (nid, uid, pkey, pval) "
      + " values (?, ?, ?, ?)";
    insert_key_val_st = conn.prepareStatement(query);

    query =  "delete from " + pairs_tbl
      + " where (nid = ?) AND (pkey = ?)";
    remove_key_data_st = conn.prepareStatement(query);

    query = (derby_mode ? DERBY_CONNVALID_QUERY : JDBC_CONNVALID_QUERY);
    conn_valid_st = conn.prepareStatement(query);
  }

  // Implementation of tigase.db.UserRepository

  private void checkDBSchema() {
    String schema_version = "1.0";
    try {
      String query =
        (derby_mode ? DERBY_GETSCHEMAVER_QUERY : JDBC_GETSCHEMAVER_QUERY);
      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery(query);
      if (rs.next()) {
        schema_version = rs.getString(1);
        if ("4.0".equals(schema_version)) {
          return;
        }
      }
      throw new TigaseDBException("Incorect DB schema version.");
    } catch (Exception e) {
      System.err.println("\n\nPlease upgrade database schema now.");
      System.err.println("Current scheme version is: " + schema_version
        + ", expected: 4.0");
      System.err.println("Check the schema upgrade guide at the address:");
      System.err.println("http://www.tigase.org/en/mysql-db-schema-upgrade-4-0");
      System.err.println("----");
      System.err.println("If you have upgraded your schema and you are still");
      System.err.println("experiencing this problem please contact support at");
      System.err.println("e-mail address: support@tigase.org");
      //e.printStackTrace();
      System.exit(100);
    }
  }

  private void initRepo() throws SQLException {
    Statement stmt = null;
    ResultSet rs = null;
    try {
      synchronized (db_conn) {
        conn = DriverManager.getConnection(db_conn);
        conn.setAutoCommit(true);
        derby_mode = db_conn.startsWith("jdbc:derby");
        checkDBSchema();
        initPreparedStatements();
        auth = new UserAuthRepositoryImpl(this);
        stmt = conn.createStatement();
        //       // load maximum ids
        //       String query = "SELECT max_uid, max_nid FROM " + maxids_tbl;
        //       rs = stmt.executeQuery(query);
        //       rs.next();
        //       max_uid = rs.getLong("max_uid");
        //       max_nid = rs.getLong("max_nid");
        if (db_conn.contains("cacheRepo=off")) {
          log.fine("Disabling cache.");
          cache = Collections.synchronizedMap(new RepoCache(0, -1000));
        } else {
          cache = Collections.synchronizedMap(new RepoCache(10000, 60*1000));
        }
      }
    } finally {
      release(stmt, rs);
      stmt = null; rs = null;
    }
  }

  public String getResourceUri() { return db_conn; }

  /**
   * Describe <code>initRepository</code> method here.
   *
   * @param connection_str a <code>String</code> value
   */
  public void initRepository(final String connection_str,
    Map<String, String> params) throws DBInitException {
    db_conn = connection_str;
    if (db_conn.contains("autoCreateUser=true")) {
      autoCreateUser=true;
    } // end of if (db_conn.contains())
    try {
      initRepo();
      log.info("Initialized database connection: " + connection_str);
    } catch (SQLException e) {
      conn = null;
      throw  new DBInitException("Problem initializing jdbc connection: "
        + db_conn, e);
    }
  }

  /**
   * <code>getUsersCount</code> method is thread safe. It uses local variable
   * for storing <code>Statement</code>.
   *
   * @return a <code>long</code> number of user accounts in database.
   */
  public long getUsersCount() {
    ResultSet rs = null;
    try {
      checkConnection();
      // Load all user count from database
      rs = users_count_sp.executeQuery();
      long users = -1;
      if (rs.next()) {
        users = rs.getLong(1);
      } // end of while (rs.next())
      return users;
    } catch (SQLException e) {
      return -1;
      //throw new TigaseDBException("Problem loading user list from repository", e);
    } finally {
      release(null, rs);
      rs = null;
    }
  }

  /**
   * <code>getUsers</code> method is thread safe. It uses local variable
   * for storing <code>Statement</code>.
   *
   * @return a <code>List</code> of user IDs from database.
   */
  public List<String> getUsers() throws TigaseDBException {
    ResultSet rs = null;
    try {
      checkConnection();
      // Load all user ids from database
      rs = all_users_sp.executeQuery();
      List<String> users = new ArrayList<String>();
      while (rs.next()) {
        users.add(rs.getString(1));
      } // end of while (rs.next())
      return users;
    } catch (SQLException e) {
      throw new TigaseDBException("Problem loading user list from repository", e);
    } finally {
      release(null, rs);
      rs = null;
    }
  }

  /**
   * <code>addUserRepo</code> method is thread safe. It uses local variable
   * for storing <code>Statement</code>.
   *
   * @param user_id a <code>String</code> value of the user ID.
   * @return a <code>long</code> value of <code>uid</code> database user ID.
   * @exception SQLException if an error occurs
   */
  private long addUserRepo(final String user_id)
    throws SQLException, TigaseDBException {
    checkConnection();
    ResultSet rs = null;
    long uid = -1;
    synchronized (user_add_sp) {
      try {
        user_add_sp.setString(1, user_id);
        user_add_sp.setNull(2, Types.VARCHAR);
        rs = user_add_sp.executeQuery();
        if (rs.next()) {
          uid = rs.getLong(1);
          //addNode(uid, -1, root_node);
        } else {
          log.warning("Missing UID after adding new user...");
          throw new TigaseDBException("Propeblem adding new user to repository. "
            + "The SP should return uid or fail");
        } // end of if (isnext) else
      } finally {
        release(null, rs);
      }
    }
    cache.put(user_id, Long.valueOf(uid));
    return uid;
  }

  /**
   * Describe <code>addUser</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @exception UserExistsException if an error occurs
   */
  public void addUser(final String user_id)
    throws UserExistsException, TigaseDBException {
    try {
      addUserRepo(user_id);
    } catch (SQLException e) {
      throw new UserExistsException("Error adding user to repository: ", e);
    }
  }

  /**
   * <code>removeUser</code> method is thread safe. It uses local variable
   * for storing <code>Statement</code>.
   *
   * @param user_id a <code>String</code> value the user Jabber ID.
   * @exception UserNotFoundException if an error occurs
   */
  public void removeUser(final String user_id)
    throws UserNotFoundException, TigaseDBException {
    Statement stmt = null;
    ResultSet rs = null;
    String query = null;
    try {
      checkConnection();
      stmt = conn.createStatement();
      // Get user account uid
      long uid = getUserUID(user_id, autoCreateUser);
      // Remove all user enrties from pairs table
      query = "delete from " + pairs_tbl + " where uid = " + uid;
      stmt.executeUpdate(query);
      // Remove all user entries from nodes table
      query = "delete from " + nodes_tbl + " where uid = " + uid;
      stmt.executeUpdate(query);
      // Remove user account from users table
      user_del_sp.setString(1, user_id);
      user_del_sp.executeUpdate();
    } catch (SQLException e) {
      throw new TigaseDBException("Error removing user from repository: "
        + query, e);
    } finally {
      release(stmt, rs);
      stmt = null;
      cache.remove(user_id);
      //cache.clear();
    }
  }

  /**
   * Describe <code>getDataList</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @param key a <code>String</code> value
   * @return a <code>String[]</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public String[] getDataList(final String user_id, final String subnode,
    final String key) throws UserNotFoundException, TigaseDBException {
    //     String[] cache_res = (String[])cache.get(user_id+"/"+subnode+"/"+key);
    //     if (cache_res != null) {
    //       return cache_res;
    //     } // end of if (result != null)
    ResultSet rs = null;
    try {
      checkConnection();
      long nid = getNodeNID(user_id, subnode);
      synchronized (data_for_node_st) {
        if (nid > 0) {
          List<String> results = new ArrayList<String>();
          data_for_node_st.setLong(1, nid);
          data_for_node_st.setString(2, key);
          rs = data_for_node_st.executeQuery();
          while (rs.next()) {
            results.add(rs.getString(1));
          }
          String[] result = results.size() == 0 ? null :
            results.toArray(new String[results.size()]);
          //cache.put(user_id+"/"+subnode+"/"+key, result);
          return result;
        } else {
          return null;
        } // end of if (nid > 0) else
      }
    } catch (SQLException e) {
      throw new TigaseDBException("Error getting data list.", e);
    } finally {
      release(null, rs);
    }
  }

  /**
   * Describe <code>getSubnodes</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @return a <code>String[]</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public String[] getSubnodes(final String user_id,  final String subnode)
    throws UserNotFoundException, TigaseDBException {
    ResultSet rs = null;
    try {
      checkConnection();
      long nid = getNodeNID(user_id, subnode);
      synchronized (nodes_for_node_st) {
        if (nid > 0) {
          List<String> results = new ArrayList<String>();
          nodes_for_node_st.setLong(1, nid);
          rs = nodes_for_node_st.executeQuery();
          while (rs.next()) {
            results.add(rs.getString(2));
          }
          return results.size() == 0 ? null :
            results.toArray(new String[results.size()]);
        } else {
          return null;
        } // end of if (nid > 0) else
      }
    } catch (SQLException e) {
      throw new TigaseDBException("Error getting subnodes list.", e);
    } finally {
      release(null, rs);
    }
  }

  /**
   * Describe <code>getSubnodes</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @return a <code>String[]</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public String[] getSubnodes(final String user_id)
    throws UserNotFoundException, TigaseDBException {
    return getSubnodes(user_id, null);
  }

  private void deleteSubnode(long nid) throws SQLException {
    Statement stmt = null;
    ResultSet rs = null;
    String query = null;
    try {
      stmt = conn.createStatement();
      query = "delete from " + pairs_tbl + " where nid = " + nid;
      stmt.executeUpdate(query);
      query = "delete from " + nodes_tbl + " where nid = " + nid;
      stmt.executeUpdate(query);
      // I am not really sure if this is correct. Besides, it is not save for
      // many JDBC drivers to call a query while reading results from another
      // query.
//       query = "select nid from " + nodes_tbl + " where parent_nid = " + nid;
//       rs = stmt.executeQuery(query);
//       while (rs.next()) {
//         long subnode_nid = rs.getLong(1);
//         deleteSubnode(subnode_nid);
//       } // end of while (rs.next())
    } finally {
      release(stmt, rs);
    }
  }

  /**
   * Describe <code>removeSubnode</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public void removeSubnode(final String user_id,  final String subnode)
    throws UserNotFoundException, TigaseDBException {
    if (subnode == null) {
      return;
    } // end of if (subnode == null)
    try {
      checkConnection();
      long nid = getNodeNID(user_id, subnode);
      if (nid > 0) {
        deleteSubnode(nid);
        cache.remove(user_id+"/"+subnode);
      }
    } catch (SQLException e) {
      throw new TigaseDBException("Error getting subnodes list.", e);
    }
  }

  /**
   * Describe <code>setDataList</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @param key a <code>String</code> value
   * @param list a <code>String[]</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public void setDataList(final String user_id, final String subnode,
    final String key, final String[] list)
    throws UserNotFoundException, TigaseDBException {
    removeData(user_id, subnode, key);
    addDataList(user_id, subnode, key, list);
  }

  /**
   * Describe <code>addDataList</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @param key a <code>String</code> value
   * @param list a <code>String[]</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public void addDataList(final String user_id, final String subnode,
    final String key, final String[] list)
    throws UserNotFoundException, TigaseDBException {
    long uid = -2;
    long nid = -2;
    try {
      checkConnection();
      uid = getUserUID(user_id, autoCreateUser);
      nid = getNodeNID(uid, subnode);
      if (nid < 0) {
        nid = createNodePath(user_id, subnode);
      }
      synchronized (insert_key_val_st) {
        insert_key_val_st.setLong(1, nid);
        insert_key_val_st.setLong(2, uid);
        insert_key_val_st.setString(3, key);
        for (String val: list) {
          insert_key_val_st.setString(4, val);
          insert_key_val_st.executeUpdate();
        } // end of for (String val: list)
      }
    } catch (SQLException e) {
      throw new TigaseDBException("Error adding data list, user_id: " + user_id
        + ", subnode: " + subnode + ", key: " + key
        + ", uid: " + uid + ", nid: " + nid
        + ", list: " + Arrays.toString(list), e);
    }
    //    cache.put(user_id+"/"+subnode+"/"+key, list);
  }

  /**
   * Describe <code>getKeys</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @return a <code>String[]</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public String[] getKeys(final String user_id, final String subnode)
    throws UserNotFoundException, TigaseDBException {
    ResultSet rs = null;
    try {
      checkConnection();
      long nid = getNodeNID(user_id, subnode);
      if (nid > 0) {
        List<String> results = new ArrayList<String>();
        synchronized (keys_for_node_st) {
          keys_for_node_st.setLong(1, nid);
          rs = keys_for_node_st.executeQuery();
          while (rs.next()) {
            results.add(rs.getString(1));
          }
          return results.size() == 0 ? null :
            results.toArray(new String[results.size()]);
        }
      } else {
        return null;
      } // end of if (nid > 0) else
    } catch (SQLException e) {
      throw new TigaseDBException("Error getting subnodes list.", e);
    } finally {
      release(null, rs);
    }
  }

  /**
   * Describe <code>getKeys</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @return a <code>String[]</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public String[] getKeys(final String user_id)
    throws UserNotFoundException, TigaseDBException {
    return getKeys(user_id, null);
  }

  /**
   * Describe <code>getData</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @param key a <code>String</code> value
   * @param def a <code>String</code> value
   * @return a <code>String</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public String getData(final String user_id, final String subnode,
    final String key, final String def)
    throws UserNotFoundException, TigaseDBException {
    //     String[] cache_res = (String[])cache.get(user_id+"/"+subnode+"/"+key);
    //     if (cache_res != null) {
    //       return cache_res[0];
    //     } // end of if (result != null)
    ResultSet rs = null;
    try {
      checkConnection();
      long nid = getNodeNID(user_id, subnode);
      synchronized (data_for_node_st) {
        if (nid > 0) {
          String result = def;
          data_for_node_st.setLong(1, nid);
          data_for_node_st.setString(2, key);
          rs = data_for_node_st.executeQuery();
          if (rs.next()) {
            result = rs.getString(1);
          }
          //cache.put(user_id+"/"+subnode+"/"+key, new String[] {result});
          return result;
        } else {
          return def;
        } // end of if (nid > 0) else
      }
    } catch (SQLException e) {
      throw new TigaseDBException("Error getting data list.", e);
    } finally {
      release(null, rs);
    }
  }

  /**
   * Describe <code>getData</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @param key a <code>String</code> value
   * @return a <code>String</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public String getData(final String user_id, final String subnode,
    final String key) throws UserNotFoundException, TigaseDBException {
    return getData(user_id, subnode, key, null);
  }

  /**
   * Describe <code>getData</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param key a <code>String</code> value
   * @return a <code>String</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public String getData(final String user_id,  final String key)
    throws UserNotFoundException, TigaseDBException {
    return getData(user_id, null, key, null);
  }

  /**
   * Describe <code>setData</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @param key a <code>String</code> value
   * @param value a <code>String</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public void setData(final String user_id, final String subnode,
    final String key, final String value)
    throws UserNotFoundException, TigaseDBException {
    setDataList(user_id, subnode, key, new String[] {value});
  }

  /**
   * Describe <code>setData</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param key a <code>String</code> value
   * @param value a <code>String</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public void setData(final String user_id, final String key,
    final String value)
    throws UserNotFoundException, TigaseDBException {
    setData(user_id, null, key, value);
  }

  /**
   * Describe <code>removeData</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param subnode a <code>String</code> value
   * @param key a <code>String</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public void removeData(final String user_id, final String subnode,
    final String key)
    throws UserNotFoundException, TigaseDBException {
    //    cache.remove(user_id+"/"+subnode+"/"+key);
    try {
      checkConnection();
      long nid = getNodeNID(user_id, subnode);
      synchronized (remove_key_data_st) {
        if (nid > 0) {
          remove_key_data_st.setLong(1, nid);
          remove_key_data_st.setString(2, key);
          remove_key_data_st.executeUpdate();
        }
      }
    } catch (SQLException e) {
      throw new TigaseDBException("Error getting subnodes list.", e);
    }
  }

  /**
   * Describe <code>removeData</code> method here.
   *
   * @param user_id a <code>String</code> value
   * @param key a <code>String</code> value
   * @exception UserNotFoundException if an error occurs
   */
  public void removeData(final String user_id, final String key)
    throws UserNotFoundException, TigaseDBException {
    removeData(user_id, null, key);
  }

  // Implementation of tigase.db.UserAuthRepository

  /**
   * Describe <code>plainAuth</code> method here.
   *
   * @param user a <code>String</code> value
   * @param password a <code>String</code> value
   * @return a <code>boolean</code> value
   * @exception UserNotFoundException if an error occurs
   * @exception TigaseDBException if an error occurs
   */
  public boolean plainAuth(final String user, final String password)
    throws UserNotFoundException, TigaseDBException, AuthorizationException {
    return auth.plainAuth(user, password);
  }

  /**
   * Describe <code>digestAuth</code> method here.
   *
   * @param user a <code>String</code> value
   * @param digest a <code>String</code> value
   * @param id a <code>String</code> value
   * @param alg a <code>String</code> value
   * @return a <code>boolean</code> value
   * @exception UserNotFoundException if an error occurs
   * @exception TigaseDBException if an error occurs
   */
  public boolean digestAuth(final String user, final String digest,
    final String id, final String alg)
    throws UserNotFoundException, TigaseDBException, AuthorizationException {
    return auth.digestAuth(user, digest, id, alg);
  }

  /**
   * Describe <code>otherAuth</code> method here.
   *
   * @param props a <code>Map</code> value
   * @return a <code>boolean</code> value
   * @exception UserNotFoundException if an error occurs
   * @exception TigaseDBException if an error occurs
   * @exception AuthorizationException if an error occurs
   */
  public boolean otherAuth(final Map<String, Object> props)
    throws UserNotFoundException, TigaseDBException, AuthorizationException {
    return auth.otherAuth(props);
  }

  public void updatePassword(final String user, final String password)
    throws TigaseDBException {
    auth.updatePassword(user, password);
  }

  public void logout(final String user)
    throws UserNotFoundException, TigaseDBException {
    auth.logout(user);
  }

  /**
   * Describe <code>addUser</code> method here.
   *
   * @param user a <code>String</code> value
   * @param password a <code>String</code> value
   * @exception UserExistsException if an error occurs
   * @exception TigaseDBException if an error occurs
   */
  public void addUser(final String user, final String password)
    throws UserExistsException, TigaseDBException {
    auth.addUser(user, password);
  }

  public void queryAuth(Map<String, Object> authProps) {
    auth.queryAuth(authProps);
  }

  private class RepoCache extends SimpleCache<String, Object> {

    public RepoCache(int maxsize, long cache_time) {
      super(maxsize, cache_time);
    }

    public Object remove(Object key) {
      if (cache_off) { return null; }

      Object val = super.remove(key);
      String strk = key.toString();
      Iterator<String> ks = keySet().iterator();
      while (ks.hasNext()) {
        String k = ks.next().toString();
        if (k.startsWith(strk)) {
          ks.remove();
        } // end of if (k.startsWith(strk))
      } // end of while (ks.hasNext())
      return val;
    }

  }

} // JDBCRepository
TOP

Related Classes of tigase.db.jdbc.JDBCRepository$RepoCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.