org.jivesoftware.openfire.roster.HimRosterItemProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.jivesoftware.openfire.roster.HimRosterItemProvider.java

Source

/**
 * $RCSfile$
 * $Revision: 1751 $
 * $Date: 2005-08-07 20:08:47 -0300 (Sun, 07 Aug 2005) $
 *
 * Copyright (C) 2005-2008 Jive Software. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jivesoftware.openfire.roster;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.LocaleUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoClient;
import com.mongodb.WriteResult;

/**
 * Defines the provider methods required for creating, reading, updating and
 * deleting roster items.
 * <p>
 * 
 * Rosters are another user resource accessed via the user or chatbot's long ID.
 * A user/chatbot may have zero or more roster items and each roster item may
 * have zero or more groups. Each roster item is additionaly keyed on a XMPP
 * jid. In most cases, the entire roster will be read in from memory and
 * manipulated or sent to the user. However some operations will need to retrive
 * specific roster items rather than the entire roster.
 * 
 * @author Aniyus
 */
public class HimRosterItemProvider implements RosterItemProvider {

    private static final Logger Log = LoggerFactory.getLogger(HimRosterItemProvider.class);
    boolean initilized = false;
    private static final String CREATE_ROSTER_ITEM = "INSERT INTO ofRoster (username, rosterID, jid, sub, ask, recv, nick,version) "
            + "VALUES (?, ?, ?, ?, ?, ?, ?,?)";
    private static final String UPDATE_ROSTER_ITEM = "UPDATE ofRoster SET sub=?, ask=?, recv=?, nick=?,version=? WHERE rosterID=?";
    private static final String DELETE_ROSTER_ITEM_GROUPS = "DELETE FROM ofRosterGroups WHERE rosterID=?";
    private static final String CREATE_ROSTER_ITEM_GROUPS = "INSERT INTO ofRosterGroups (rosterID, rank, groupName) VALUES (?, ?, ?)";
    private static final String DELETE_ROSTER_ITEM = "DELETE FROM ofRoster WHERE rosterID=?";
    private static final String LOAD_USERNAMES = "SELECT DISTINCT username from ofRoster WHERE jid=?";
    private static final String COUNT_ROSTER_ITEMS = "SELECT COUNT(rosterID) FROM ofRoster WHERE username=?";
    private static final String LOAD_ROSTER = "SELECT jid, rosterID, sub, ask, recv, nick,version FROM ofRoster WHERE username=?";
    private static final String LOAD_ROSTER_ITEM_GROUPS = "SELECT rosterID,groupName FROM ofRosterGroups";

    private MongoClient mongoClient;
    private DB db = null;

    public HimRosterItemProvider() {
        // TODO Auto-generated constructor stub
        init();
    }

    private void init() {
        if (initilized)
            return;
        String hostname = JiveGlobals.getXMLProperty("him.central.dbhost", "localhost");
        int port = JiveGlobals.getXMLProperty("him.central.dbport", 27017);
        String login = JiveGlobals.getXMLProperty("him.central.dblogin", null);
        String passwd = JiveGlobals.getXMLProperty("him.central.dbpassword", null);
        String dbSchema = JiveGlobals.getXMLProperty("him.central.dbschema", "hereiam");
        try {
            mongoClient = new MongoClient(hostname, port);
            db = mongoClient.getDB(dbSchema);
            if (login != null && !db.authenticate(login, passwd.toCharArray())) {
                throw new Exception("invalid credential");
            }
            initilized = true;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            mongoClient = null;
            db = null;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.jivesoftware.openfire.roster.RosterItemProvider#createItem(java.lang
     * .String, org.jivesoftware.openfire.roster.RosterItem)
     */
    public RosterItem createItem(String username, RosterItem item) throws UserAlreadyExistsException {

        try {

            DBCollection coll = db.getCollection("gUser");

            BasicDBObject doc = new BasicDBObject("name", item.getNickname()).append("himId", username)
                    .append("sub", item.getSubStatus().getValue()).append("ask", item.getAskStatus().getValue())
                    .append("recv", item.getRecvStatus().getValue()).append("currVer", item.getCurrVersion())
                    .append("groupName", item.getGroups());

            ;
            BasicDBObject q = new BasicDBObject("himId", username);
            //   INSERT INTO ofRoster (username, rosterID, jid, sub, ask, recv, nick,version) 
            WriteResult res = coll.update(q, new BasicDBObject("$push", new BasicDBObject("friends", doc)));

        } catch (Exception e) {
            Log.warn("Error trying to insert a new row in ofRoster", e);
            throw new UserAlreadyExistsException(item.getJid().toBareJID());
        }
        return item;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.jivesoftware.openfire.roster.RosterItemProvider#updateItem(java.lang
     * .String, org.jivesoftware.openfire.roster.RosterItem)
     */
    public void updateItem(String username, RosterItem item) throws UserNotFoundException {
        Connection con = null;
        PreparedStatement pstmt = null;
        long rosterID = item.getID();
        try {
            item.setCurrVersion(System.currentTimeMillis());
            con = DbConnectionManager.getConnection();
            // Update existing roster item
            pstmt = con.prepareStatement(UPDATE_ROSTER_ITEM);
            pstmt.setInt(1, item.getSubStatus().getValue());
            pstmt.setInt(2, item.getAskStatus().getValue());
            pstmt.setInt(3, item.getRecvStatus().getValue());
            pstmt.setString(4, item.getNickname());
            pstmt.setLong(5, rosterID);
            pstmt.setLong(6, item.getCurrVersion());
            pstmt.executeUpdate();
            // Close now the statement (do not wait to be GC'ed)
            DbConnectionManager.fastcloseStmt(pstmt);

            // Delete old group list
            pstmt = con.prepareStatement(DELETE_ROSTER_ITEM_GROUPS);
            pstmt.setLong(1, rosterID);
            pstmt.executeUpdate();

            insertGroups(rosterID, item.getGroups().iterator(), con);
        } catch (SQLException e) {
            Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
        } finally {
            DbConnectionManager.closeConnection(pstmt, con);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.jivesoftware.openfire.roster.RosterItemProvider#deleteItem(java.lang
     * .String, long)
     */
    public void deleteItem(String username, long rosterItemID) {
        // Only try to remove the user if they exist in the roster already:
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = DbConnectionManager.getConnection();
            // Remove roster groups
            pstmt = con.prepareStatement(DELETE_ROSTER_ITEM_GROUPS);

            pstmt.setLong(1, rosterItemID);
            pstmt.executeUpdate();
            // Close now the statement (do not wait to be GC'ed)
            DbConnectionManager.fastcloseStmt(pstmt);

            // Remove roster
            pstmt = con.prepareStatement(DELETE_ROSTER_ITEM);

            pstmt.setLong(1, rosterItemID);
            pstmt.executeUpdate();
        } catch (SQLException e) {
            Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
        } finally {
            DbConnectionManager.closeConnection(pstmt, con);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.jivesoftware.openfire.roster.RosterItemProvider#getUsernames(java
     * .lang.String)
     */
    public Iterator<String> getUsernames(String jid) {
        List<String> answer = new ArrayList<String>();
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(LOAD_USERNAMES);
            pstmt.setString(1, jid);
            rs = pstmt.executeQuery();
            while (rs.next()) {
                answer.add(rs.getString(1));
            }
        } catch (SQLException e) {
            Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
        } finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        return answer.iterator();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.jivesoftware.openfire.roster.RosterItemProvider#getItemCount(java
     * .lang.String)
     */
    public int getItemCount(String username) {
        int count = 0;
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(COUNT_ROSTER_ITEMS);
            pstmt.setString(1, username);
            rs = pstmt.executeQuery();
            if (rs.next()) {
                count = rs.getInt(1);
            }
        } catch (SQLException e) {
            Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
        } finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        return count;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.jivesoftware.openfire.roster.RosterItemProvider#getItems(java.lang
     * .String)
     */
    public Iterator<RosterItem> getItems(String username) {
        LinkedList<RosterItem> itemList = new LinkedList<RosterItem>();
        Map<Long, RosterItem> itemsByID = new HashMap<Long, RosterItem>();
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            // Load all the contacts in the roster
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(LOAD_ROSTER);
            pstmt.setString(1, username);
            rs = pstmt.executeQuery();
            while (rs.next()) {
                // Create a new RosterItem (ie. user contact) from the stored
                // information
                RosterItem item = new RosterItem(rs.getLong(2), new JID(rs.getString(1)),
                        RosterItem.SubType.getTypeFromInt(rs.getInt(3)),
                        RosterItem.AskType.getTypeFromInt(rs.getInt(4)),
                        RosterItem.RecvType.getTypeFromInt(rs.getInt(5)), rs.getString(6), null);
                item.setCurrVersion(rs.getLong(7));
                // Add the loaded RosterItem (ie. user contact) to the result
                itemList.add(item);
                itemsByID.put(item.getID(), item);
            }
            // Close the statement and result set
            DbConnectionManager.fastcloseStmt(rs, pstmt);
            // Set null to pstmt to be sure that it's not closed twice. It seems
            // that
            // Sybase driver is raising an error when trying to close an already
            // closed statement.
            // it2000 comment: TODO interesting, that's the only place with the
            // sybase fix
            // it2000 comment: one should move this in closeStatement()
            pstmt = null;

            // Load the groups for the loaded contact
            if (!itemList.isEmpty()) {
                StringBuilder sb = new StringBuilder(100);
                sb.append(LOAD_ROSTER_ITEM_GROUPS).append(" WHERE rosterID IN (");
                for (RosterItem item : itemList) {
                    sb.append(item.getID()).append(",");
                }
                sb.setLength(sb.length() - 1);
                sb.append(") ORDER BY rosterID, rank");
                pstmt = con.prepareStatement(sb.toString());
                rs = pstmt.executeQuery();
                while (rs.next()) {
                    itemsByID.get(rs.getLong(1)).getGroups().add(rs.getString(2));
                }
            }
        } catch (SQLException e) {
            Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
        } finally {
            DbConnectionManager.closeConnection(rs, pstmt, con);
        }
        return itemList.iterator();
    }

    /**
     * Insert the groups into the given roster item.
     * 
     * @param rosterID
     *            the roster ID of the item the groups belong to
     * @param iter
     *            an iterator over the group names to insert
     * @param con
     *            the database connection to use for the operation.
     * @throws SQLException
     *             if an SQL exception occurs.
     */
    private void insertGroups(long rosterID, Iterator<String> iter, Connection con) throws SQLException {
        PreparedStatement pstmt = null;
        try {
            pstmt = con.prepareStatement(CREATE_ROSTER_ITEM_GROUPS);
            pstmt.setLong(1, rosterID);
            for (int i = 0; iter.hasNext(); i++) {
                pstmt.setInt(2, i);
                String groupName = iter.next();
                pstmt.setString(3, groupName);
                try {
                    pstmt.executeUpdate();
                } catch (SQLException e) {
                    Log.error(e.getMessage(), e);
                }
            }
        } finally {
            DbConnectionManager.closeStatement(pstmt);
        }
    }

    @Override
    public void deleteItem(String username, String rosterItemID) {
        // TODO Auto-generated method stub

    }
}