com.extrahardmode.module.MsgPersistModule.java Source code

Java tutorial

Introduction

Here is the source code for com.extrahardmode.module.MsgPersistModule.java

Source

/*
 * This file is part of
 * ExtraHardMode Server Plugin for Minecraft
 *
 * Copyright (C) 2012 Ryan Hamshire
 * Copyright (C) 2013 Diemex
 *
 * ExtraHardMode is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ExtraHardMode 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 Affero Public License
 * along with ExtraHardMode.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.extrahardmode.module;

import com.extrahardmode.ExtraHardMode;
import com.extrahardmode.config.messages.MessageConfig;
import com.extrahardmode.config.messages.MessageNode;
import com.extrahardmode.config.messages.MsgCategory;
import com.extrahardmode.service.EHMModule;
import com.google.common.collect.Table;
import org.apache.commons.lang.Validate;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;

/** @author Diemex */
public class MsgPersistModule extends EHMModule {
    private final String dbFile;

    private final String msgTable = "messages";

    private final String playerTable = "players";

    private MessageConfig messages;

    /** Buffer player ids (playerName, playerId) */
    private Map<String, Integer> playerIdBuffer;

    /** Buffer data from the db (playerid, message, value) */
    private Table<Integer, MessageNode, Integer> buffer;

    /**
     * Constructor.
     *
     * @param plugin - Plugin instance.
     */
    public MsgPersistModule(ExtraHardMode plugin, String dbFile) {
        super(plugin);
        this.dbFile = dbFile;
    }

    @Override
    public void starting() {
        messages = plugin.getModuleForClass(MessageConfig.class);
        playerIdBuffer = new HashMap<String, Integer>();
        testJDBC();
        initializeTables();
    }

    @Override
    public void closing() {
        playerIdBuffer = null;
    }

    /** Make sure JDBC is enabled/loaded */
    protected void testJDBC() {
        try {
            Class.forName("org.sqlite.JDBC");
        } catch (ClassNotFoundException e) {
            plugin.getLogger().severe("JDBC Driver not found : " + e);
            closing();
        }
    }

    /**
     * Get the id of the Player. Buffers id in a Map. Creates new id if Player not in the db yet.
     *
     * @param playerName name of the Player
     *
     * @return id of Player
     */
    private int getPlayerId(String playerName) {
        if (playerIdBuffer.containsKey(playerName))
            return playerIdBuffer.get(playerName);
        int id = 0;

        Connection conn = null;
        Statement aStatement = null;
        ResultSet resultSet = null;
        try {
            conn = retrieveConnection();
            aStatement = conn.createStatement();
            String playerIdQuery = String.format("SELECT id FROM %s WHERE %s = %s", playerTable, "name",
                    '"' + playerName + '"');

            resultSet = aStatement.executeQuery(playerIdQuery);
            if (resultSet.next())
                id = resultSet.getInt("id");

            if (id == 0) //Create a new Player
            {
                String newPlayerQuery = String.format( //new id
                        "INSERT INTO %s (%s) VALUES (%s)", playerTable, "name", '"' + playerName + '"');
                aStatement.executeUpdate(newPlayerQuery);

                //Get the id of the just inserted row, I tried getGeneratedKeys() but that wasn't supported by jdbc
                resultSet = aStatement.executeQuery(playerIdQuery);
                if (resultSet.next())
                    id = resultSet.getInt("id");

                String newPlayerDataQuery = String.format( //empty row in messages
                        "INSERT INTO %s (%s) VALUES (%s)", msgTable, "id", id);
                aStatement.executeUpdate(newPlayerDataQuery);
                aStatement.close();
            }

            playerIdBuffer.put(playerName, id);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (conn != null)
                    conn.close();
                if (aStatement != null)
                    aStatement.close();
                if (resultSet != null)
                    resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return id;
    }

    /**
     * Get a connection to our database
     *
     * @return a connection
     */
    private Connection retrieveConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:sqlite:" + dbFile);
    }

    /** Creates tables if they do not exist. */
    private void initializeTables() {
        Connection conn = null;
        Statement statement = null;
        try {
            conn = retrieveConnection();
            statement = conn.createStatement();
            statement.setQueryTimeout(30);

            //One table holding the playername id relation
            String playerQuery = String.format(
                    "CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY AUTOINCREMENT, %s STRING)", playerTable,
                    "name");
            statement.executeUpdate(playerQuery);

            //One column for every message
            StringBuilder columns = new StringBuilder();
            for (MessageNode node : MessageNode.getMessageNodes()) {
                MsgCategory cat = messages.getCat(node);
                if (node.getColumnName() != null && (cat == MsgCategory.TUTORIAL || cat == MsgCategory.ONE_TIME)) {
                    columns.append(',');
                    columns.append(node.getColumnName());
                }
            }

            String msgQuery = String.format("CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY UNIQUE %s)",
                    msgTable, columns);
            statement.executeUpdate(msgQuery);

            //Check if all columns are present
            DatabaseMetaData dmd = conn.getMetaData();
            //Add missing columns
            for (MessageNode node : MessageNode.getMessageNodes()) {
                MsgCategory cat = messages.getCat(node);
                if (cat == MsgCategory.TUTORIAL || cat == MsgCategory.ONE_TIME) {
                    ResultSet set = dmd.getColumns(null, null, msgTable, node.getColumnName());
                    if (!set.next()) {
                        String updateQuery = String.format("ALTER TABLE %s ADD COLUMN %s", msgTable,
                                node.getColumnName());
                        statement.executeUpdate(updateQuery);
                    }
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (conn != null)
                    conn.close();
                if (statement != null)
                    statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Increment the count of a certain message by one
     *
     * @param node       to increment
     * @param playerName only for this player
     */
    public void increment(MessageNode node, String playerName) {
        int playerId = getPlayerId(playerName);
        int value = getCountFor(node, playerId);

        set(node, playerId, ++value);
    }

    /**
     * Set the count of a certain message to a certain value
     *
     * @param node     node to set the count for
     * @param playerId player for whom we are tracking the count
     * @param value    value to set
     */
    private void set(MessageNode node, int playerId, int value) {
        Validate.isTrue(value >= 0, "Count has to be positive");
        Connection conn = null;
        Statement statement = null;
        try {
            conn = retrieveConnection();
            statement = conn.createStatement();

            //Set the count to the provided value
            String setQuery = String.format("UPDATE %s SET %s = %s WHERE id = %s", msgTable, node.getColumnName(),
                    value, playerId);
            statement.execute(setQuery);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (conn != null)
                    conn.close();
                if (statement != null)
                    statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Get the count of a message
     *
     * @param node       which message
     * @param playerName player which has seen this message
     *
     * @return count >= 0
     */
    public int getCountFor(MessageNode node, String playerName) {
        return getCountFor(node, getPlayerId(playerName));
    }

    /**
     * Get how often a message has been displayed
     *
     * @param node     to get the count for
     * @param playerId id of the player to get the count for
     *
     * @return how often this message has been displayed
     */
    private int getCountFor(MessageNode node, int playerId) {
        Connection conn = null;
        Statement statement = null;
        ResultSet result = null;
        int value = 0;

        try {
            conn = retrieveConnection();
            statement = conn.createStatement();

            String select = String.format("SELECT * FROM %s WHERE %s = %s", msgTable, "id", playerId);

            result = statement.executeQuery(select);
            if (result.next())
                value = result.getInt(node.getColumnName());
            else //create the missing row
            {
                String newPlayerDataQuery = String.format( //empty row in messages
                        "INSERT INTO %s (%s) VALUES (%s)", msgTable, "id", playerId);
                conn.createStatement().executeUpdate(newPlayerDataQuery);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (conn != null)
                    conn.close();
                if (statement != null)
                    statement.close();
                if (result != null)
                    result.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return value;
    }

    /**
     * Resets all counts for a given player
     *
     * @param playerName player to reset the stats for
     */
    public void resetAll(String playerName) {
        int playerId = getPlayerId(playerName);
        for (MessageNode node : MessageNode.values()) {
            if (node.getColumnName() != null) {
                set(node, playerId, 0);
            }
        }
    }
}