Database.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. package com.gmail.nossr50;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. import java.sql.PreparedStatement;
  7. import java.util.HashMap;
  8. import java.util.ArrayList;
  9. import java.util.Properties;
  10. import org.bukkit.Bukkit;
  11. import org.bukkit.entity.Player;
  12. import com.gmail.nossr50.config.LoadProperties;
  13. import com.gmail.nossr50.datatypes.DatabaseUpdate;
  14. import com.gmail.nossr50.datatypes.PlayerProfile;
  15. public class Database {
  16. private String connectionString = "jdbc:mysql://" + LoadProperties.MySQLserverName + ":" + LoadProperties.MySQLport + "/" + LoadProperties.MySQLdbName + "?user=" + LoadProperties.MySQLuserName + "&password=" + LoadProperties.MySQLdbPass;
  17. private Connection conn = null;
  18. private mcMMO plugin = null;
  19. private long reconnectTimestamp = 0;
  20. public Database(mcMMO instance) {
  21. plugin = instance;
  22. connect(); //Connect to MySQL
  23. // Load the driver instance
  24. try {
  25. Class.forName("com.mysql.jdbc.Driver");
  26. DriverManager.getConnection(connectionString);
  27. }
  28. catch (ClassNotFoundException e) {
  29. Bukkit.getLogger().warning(e.getLocalizedMessage());
  30. }
  31. catch (SQLException ex) {
  32. Bukkit.getLogger().warning(ex.getLocalizedMessage());
  33. printErrors(ex);
  34. }
  35. }
  36. /**
  37. * Attempt to connect to the mySQL database.
  38. */
  39. public void connect() {
  40. try {
  41. System.out.println("[mcMMO] Attempting connection to MySQL...");
  42. Properties conProperties = new Properties();
  43. conProperties.put("autoReconnect", "false");
  44. conProperties.put("maxReconnects", "0");
  45. conn = DriverManager.getConnection(connectionString, conProperties);
  46. System.out.println("[mcMMO] Connection to MySQL was a success!");
  47. }
  48. catch (SQLException ex) {
  49. System.out.println("[mcMMO] Connection to MySQL failed!");
  50. ex.printStackTrace();
  51. printErrors(ex);
  52. }
  53. }
  54. /**
  55. * Attempt to create the database structure.
  56. */
  57. public void createStructure() {
  58. write("CREATE TABLE IF NOT EXISTS `" + LoadProperties.MySQLtablePrefix + "huds` (`user_id` int(10) unsigned NOT NULL,"
  59. + "`hudtype` varchar(50) NOT NULL DEFAULT '',"
  60. + "PRIMARY KEY (`user_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;");
  61. write("CREATE TABLE IF NOT EXISTS `" + LoadProperties.MySQLtablePrefix + "users` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,"
  62. + "`user` varchar(40) NOT NULL,"
  63. + "`lastlogin` int(32) unsigned NOT NULL,"
  64. + "`party` varchar(100) NOT NULL DEFAULT '',"
  65. + "PRIMARY KEY (`id`),"
  66. + "UNIQUE KEY `user` (`user`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;");
  67. write("CREATE TABLE IF NOT EXISTS `" + LoadProperties.MySQLtablePrefix + "cooldowns` (`user_id` int(10) unsigned NOT NULL,"
  68. + "`taming` int(32) unsigned NOT NULL DEFAULT '0',"
  69. + "`mining` int(32) unsigned NOT NULL DEFAULT '0',"
  70. + "`woodcutting` int(32) unsigned NOT NULL DEFAULT '0',"
  71. + "`repair` int(32) unsigned NOT NULL DEFAULT '0',"
  72. + "`unarmed` int(32) unsigned NOT NULL DEFAULT '0',"
  73. + "`herbalism` int(32) unsigned NOT NULL DEFAULT '0',"
  74. + "`excavation` int(32) unsigned NOT NULL DEFAULT '0',"
  75. + "`archery` int(32) unsigned NOT NULL DEFAULT '0',"
  76. + "`swords` int(32) unsigned NOT NULL DEFAULT '0',"
  77. + "`axes` int(32) unsigned NOT NULL DEFAULT '0',"
  78. + "`acrobatics` int(32) unsigned NOT NULL DEFAULT '0',"
  79. + "`blast_mining` int(32) unsigned NOT NULL DEFAULT '0',"
  80. + "PRIMARY KEY (`user_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;");
  81. write("CREATE TABLE IF NOT EXISTS `" + LoadProperties.MySQLtablePrefix + "skills` (`user_id` int(10) unsigned NOT NULL,"
  82. + "`taming` int(10) unsigned NOT NULL DEFAULT '0',"
  83. + "`mining` int(10) unsigned NOT NULL DEFAULT '0',"
  84. + "`woodcutting` int(10) unsigned NOT NULL DEFAULT '0',"
  85. + "`repair` int(10) unsigned NOT NULL DEFAULT '0',"
  86. + "`unarmed` int(10) unsigned NOT NULL DEFAULT '0',"
  87. + "`herbalism` int(10) unsigned NOT NULL DEFAULT '0',"
  88. + "`excavation` int(10) unsigned NOT NULL DEFAULT '0',"
  89. + "`archery` int(10) unsigned NOT NULL DEFAULT '0',"
  90. + "`swords` int(10) unsigned NOT NULL DEFAULT '0',"
  91. + "`axes` int(10) unsigned NOT NULL DEFAULT '0',"
  92. + "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0',"
  93. + "PRIMARY KEY (`user_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;");
  94. write("CREATE TABLE IF NOT EXISTS `" + LoadProperties.MySQLtablePrefix + "experience` (`user_id` int(10) unsigned NOT NULL,"
  95. + "`taming` int(10) unsigned NOT NULL DEFAULT '0',"
  96. + "`mining` int(10) unsigned NOT NULL DEFAULT '0',"
  97. + "`woodcutting` int(10) unsigned NOT NULL DEFAULT '0',"
  98. + "`repair` int(10) unsigned NOT NULL DEFAULT '0',"
  99. + "`unarmed` int(10) unsigned NOT NULL DEFAULT '0',"
  100. + "`herbalism` int(10) unsigned NOT NULL DEFAULT '0',"
  101. + "`excavation` int(10) unsigned NOT NULL DEFAULT '0',"
  102. + "`archery` int(10) unsigned NOT NULL DEFAULT '0',"
  103. + "`swords` int(10) unsigned NOT NULL DEFAULT '0',"
  104. + "`axes` int(10) unsigned NOT NULL DEFAULT '0',"
  105. + "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0',"
  106. + "PRIMARY KEY (`user_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;");
  107. checkDatabaseStructure(DatabaseUpdate.FISHING);
  108. checkDatabaseStructure(DatabaseUpdate.BLAST_MINING);
  109. }
  110. /**
  111. * Check database structure for missing values.
  112. *
  113. * @param update Type of data to check updates for
  114. */
  115. public void checkDatabaseStructure(DatabaseUpdate update) {
  116. String sql = null;
  117. ResultSet rs = null;
  118. HashMap<Integer, ArrayList<String>> Rows = new HashMap<Integer, ArrayList<String>>();
  119. switch (update) {
  120. case BLAST_MINING:
  121. sql = "SELECT * FROM `"+LoadProperties.MySQLtablePrefix+"cooldowns` ORDER BY `"+LoadProperties.MySQLtablePrefix+"cooldowns`.`blast_mining` ASC LIMIT 0 , 30";
  122. break;
  123. case FISHING:
  124. sql = "SELECT * FROM `"+LoadProperties.MySQLtablePrefix+"experience` ORDER BY `"+LoadProperties.MySQLtablePrefix+"experience`.`fishing` ASC LIMIT 0 , 30";
  125. break;
  126. default:
  127. break;
  128. }
  129. try {
  130. PreparedStatement stmt = conn.prepareStatement(sql);
  131. if (stmt.executeQuery() != null) {
  132. stmt.executeQuery();
  133. rs = stmt.getResultSet();
  134. while (rs.next()) {
  135. ArrayList<String> Col = new ArrayList<String>();
  136. for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
  137. Col.add(rs.getString(i));
  138. }
  139. Rows.put(rs.getRow(), Col);
  140. }
  141. }
  142. }
  143. catch (SQLException ex) {
  144. if (update.equals(DatabaseUpdate.BLAST_MINING)) {
  145. System.out.println("Updating mcMMO MySQL tables for Blast Mining...");
  146. write("ALTER TABLE `"+LoadProperties.MySQLtablePrefix + "cooldowns` ADD `blast_mining` int(32) NOT NULL DEFAULT '0' ;");
  147. }
  148. else if (update.equals(DatabaseUpdate.FISHING)) {
  149. System.out.println("Updating mcMMO MySQL tables for Fishing...");
  150. write("ALTER TABLE `"+LoadProperties.MySQLtablePrefix + "skills` ADD `fishing` int(10) NOT NULL DEFAULT '0' ;");
  151. write("ALTER TABLE `"+LoadProperties.MySQLtablePrefix + "experience` ADD `fishing` int(10) NOT NULL DEFAULT '0' ;");
  152. }
  153. }
  154. }
  155. /**
  156. * Attempt to write the SQL query.
  157. *
  158. * @param sql Query to write.
  159. * @return true if the query was successfully written, false otherwise.
  160. */
  161. public boolean write(String sql) {
  162. if (isConnected()) {
  163. try {
  164. PreparedStatement stmt = conn.prepareStatement(sql);
  165. stmt.executeUpdate();
  166. return true;
  167. }
  168. catch (SQLException ex) {
  169. printErrors(ex);
  170. return false;
  171. }
  172. }
  173. else {
  174. attemptReconnect();
  175. }
  176. return false;
  177. }
  178. /**
  179. * Get the Integer. Only return first row / first field.
  180. *
  181. * @param sql SQL query to execute
  182. * @return the value in the first row / first field
  183. */
  184. public Integer getInt(String sql) {
  185. ResultSet rs = null;
  186. Integer result = 0;
  187. if (isConnected()) {
  188. try {
  189. PreparedStatement stmt = conn.prepareStatement(sql);
  190. stmt = conn.prepareStatement(sql);
  191. if (stmt.executeQuery() != null) {
  192. stmt.executeQuery();
  193. rs = stmt.getResultSet();
  194. if (rs.next()) {
  195. result = rs.getInt(1);
  196. }
  197. else {
  198. result = 0;
  199. }
  200. }
  201. }
  202. catch (SQLException ex) {
  203. printErrors(ex);
  204. }
  205. }
  206. else {
  207. attemptReconnect();
  208. }
  209. return result;
  210. }
  211. /**
  212. * Get connection status
  213. *
  214. * @return the boolean value for whether or not we are connected
  215. */
  216. public boolean isConnected() {
  217. if(conn == null)
  218. return false;
  219. try {
  220. return conn.isValid(3);
  221. } catch (SQLException e) {
  222. return false;
  223. }
  224. }
  225. /**
  226. * Schedules a Sync Delayed Task with the Bukkit Scheduler to attempt reconnection after a minute has elapsed
  227. * This will check for a connection being present or not to prevent unneeded reconnection attempts
  228. */
  229. public void attemptReconnect() {
  230. if(reconnectTimestamp+60000 < System.currentTimeMillis()) //Only reconnect if another attempt hasn't been made recently
  231. {
  232. System.out.println("[mcMMO] Connection to MySQL was lost! Attempting to reconnect in 60 seconds...");
  233. reconnectTimestamp = System.currentTimeMillis();
  234. Bukkit.getScheduler().scheduleSyncDelayedTask(plugin,
  235. new Runnable() {
  236. public void run() {
  237. if (!isConnected()) {
  238. connect();
  239. if(isConnected()) {
  240. for(PlayerProfile x : Users.players.values()) {
  241. x.save(); //Save all profiles
  242. }
  243. Users.players.clear(); //Clear the profiles
  244. for(Player x : Bukkit.getOnlinePlayers()) {
  245. Users.addUser(x); //Add in new profiles, forcing them to 'load' again from MySQL
  246. }
  247. }
  248. }
  249. }
  250. }, 20*60);
  251. }
  252. }
  253. /**
  254. * Read SQL query.
  255. *
  256. * @param sql SQL query to read
  257. * @return the rows in this SQL query
  258. */
  259. public HashMap<Integer, ArrayList<String>> read(String sql) {
  260. ResultSet rs = null;
  261. HashMap<Integer, ArrayList<String>> Rows = new HashMap<Integer, ArrayList<String>>();
  262. if (isConnected()) {
  263. try {
  264. PreparedStatement stmt = conn.prepareStatement(sql);
  265. if (stmt.executeQuery() != null) {
  266. stmt.executeQuery();
  267. rs = stmt.getResultSet();
  268. while (rs.next()) {
  269. ArrayList<String> Col = new ArrayList<String>();
  270. for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
  271. Col.add(rs.getString(i));
  272. }
  273. Rows.put(rs.getRow(), Col);
  274. }
  275. }
  276. }
  277. catch (SQLException ex) {
  278. printErrors(ex);
  279. }
  280. }
  281. else {
  282. attemptReconnect();
  283. }
  284. return Rows;
  285. }
  286. private static void printErrors(SQLException ex) {
  287. System.out.println("SQLException: " + ex.getMessage());
  288. System.out.println("SQLState: " + ex.getSQLState());
  289. System.out.println("VendorError: " + ex.getErrorCode());
  290. }
  291. }