PageRenderTime 175ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/java/ru/tehkode/permissions/backends/sql/SQLEntity.java

https://gitlab.com/Slind/PermissionsEx
Java | 448 lines | 337 code | 82 blank | 29 comment | 89 complexity | c3060fe7b189ab8a03009f5fe06f714d MD5 | raw file
  1. /*
  2. * PermissionsEx - Permissions plugin for Bukkit
  3. * Copyright (C) 2011 t3hk0d3 http://www.tehkode.ru
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version 2
  8. * of the License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. package ru.tehkode.permissions.backends.sql;
  20. import java.sql.PreparedStatement;
  21. import java.sql.ResultSet;
  22. import java.sql.SQLException;
  23. import java.util.*;
  24. import ru.tehkode.permissions.PermissionEntity;
  25. import ru.tehkode.permissions.PermissionManager;
  26. import ru.tehkode.permissions.backends.SQLBackend;
  27. /**
  28. * @author code
  29. */
  30. public class SQLEntity extends PermissionEntity {
  31. public enum Type {
  32. GROUP, USER
  33. }
  34. protected SQLBackend backend;
  35. protected Map<String, List<String>> worldsPermissions = null;
  36. protected Map<String, Map<String, String>> worldsOptions = null;
  37. protected List<String> commonPermissions = null;
  38. protected Map<String, String> commonOptions = null;
  39. protected Map<String, Set<String>> parents = null;
  40. protected Type type;
  41. protected String prefix;
  42. protected String suffix;
  43. public SQLEntity(String name, PermissionManager manager, SQLEntity.Type type, SQLBackend backend) {
  44. super(name, manager);
  45. this.backend = backend;
  46. this.type = type;
  47. this.fetchInfo();
  48. this.fetchPermissions();
  49. this.fetchInheritance();
  50. }
  51. public static Set<String> getEntitiesNames(SQLConnection sql, Type type, boolean defaultOnly) {
  52. try {
  53. Set<String> entities = new HashSet<String>();
  54. ResultSet result = sql.prepAndBind("SELECT name FROM `{permissions_entity}` WHERE `type` = ? " + (defaultOnly ? " AND `default` = 1" : ""), type.ordinal()).executeQuery();
  55. while (result.next()) {
  56. entities.add(result.getString("name"));
  57. }
  58. result.close();
  59. return Collections.unmodifiableSet(entities);
  60. } catch (SQLException e) {
  61. throw new RuntimeException(e);
  62. }
  63. }
  64. @Override
  65. public String[] getWorlds() {
  66. Set<String> worlds = new HashSet<String>();
  67. worlds.addAll(worldsOptions.keySet());
  68. worlds.addAll(worldsPermissions.keySet());
  69. worlds.addAll(parents.keySet());
  70. return worlds.toArray(new String[0]);
  71. }
  72. @Override
  73. public String getPrefix(String worldName) {
  74. return (worldName == null || worldName.isEmpty()) ? this.prefix : this.getOption("prefix", worldName);
  75. }
  76. @Override
  77. public String getSuffix(String worldName) {
  78. return (worldName == null || worldName.isEmpty()) ? this.suffix : this.getOption("suffix", worldName);
  79. }
  80. @Override
  81. public void setPrefix(String prefix, String worldName) {
  82. if (worldName == null || worldName.isEmpty()) {
  83. this.prefix = prefix;
  84. this.updateInfo();
  85. } else {
  86. this.setOption("prefix", prefix, worldName);
  87. }
  88. }
  89. @Override
  90. public void setSuffix(String suffix, String worldName) {
  91. if (worldName == null || worldName.isEmpty()) {
  92. this.suffix = suffix;
  93. this.updateInfo();
  94. } else {
  95. this.setOption("suffix", suffix, worldName);
  96. }
  97. }
  98. public String[] getParentNames(String worldName) {
  99. if (this.parents == null) {
  100. this.fetchInheritance();
  101. }
  102. if (this.parents.containsKey(worldName)) {
  103. return this.parents.get(worldName).toArray(new String[0]);
  104. }
  105. return new String[0];
  106. }
  107. @Override
  108. public String[] getPermissions(String world) {
  109. List<String> permissions = new LinkedList<String>();
  110. if (commonPermissions == null) {
  111. this.fetchPermissions();
  112. }
  113. if (world != null && !world.isEmpty()) {
  114. List<String> worldPermissions = this.worldsPermissions.get(world);
  115. if (worldPermissions != null) {
  116. permissions.addAll(worldPermissions);
  117. }
  118. } else {
  119. permissions = commonPermissions;
  120. }
  121. return permissions.toArray(new String[0]);
  122. }
  123. @Override
  124. public String getOption(String option, String world, String defaultValue) {
  125. if (world != null && !world.isEmpty() && this.worldsOptions.containsKey(world)) {
  126. if (this.worldsOptions.get(world).containsKey(option)) {
  127. return this.worldsOptions.get(world).get(option);
  128. }
  129. }
  130. if ((world == null || world.isEmpty()) && this.commonOptions.containsKey(option)) {
  131. return this.commonOptions.get(option);
  132. }
  133. return defaultValue;
  134. }
  135. @Override
  136. public void setOption(String option, String value, String world) {
  137. if (option == null || option.isEmpty()) {
  138. return;
  139. }
  140. if (world == null) {
  141. world = "";
  142. }
  143. if (value == null || value.isEmpty()) {
  144. try {
  145. this.backend.getSQL().prepAndBind("DELETE FROM `{permissions}` WHERE `name` = ? AND `permission` = ? AND `type` = ? AND `world` = ?", this.getName(), option, this.type.ordinal(), world).execute();
  146. } catch (SQLException e) {
  147. throw new RuntimeException(e);
  148. }
  149. if (!world.isEmpty() && this.worldsOptions.containsKey(world)) {
  150. this.worldsOptions.get(world).remove(option);
  151. } else {
  152. this.commonOptions.remove(option);
  153. }
  154. return;
  155. }
  156. Boolean newOption = true;
  157. if (this.commonOptions == null) {
  158. this.fetchPermissions();
  159. }
  160. if (!world.isEmpty() && worldsOptions.containsKey(world) && worldsOptions.get(world).containsKey(option)) {
  161. newOption = false;
  162. } else if (world.isEmpty() && commonOptions.containsKey(option)) {
  163. newOption = false;
  164. }
  165. try {
  166. if (newOption) {
  167. this.backend.getSQL().prepAndBind("INSERT INTO `{permissions}` (`name`, `permission`, `value`, `world`, `type`) VALUES (?, ?, ?, ?, ?)", this.getName(), option, value, world, this.type.ordinal()).execute();
  168. } else {
  169. this.backend.getSQL().prepAndBind("UPDATE `{permissions}` SET `value` = ? WHERE `name` = ? AND `type` = ? AND `permission` = ?", value, this.getName(), this.type.ordinal(), option).execute();
  170. }
  171. } catch (SQLException e) {
  172. throw new RuntimeException(e);
  173. }
  174. if (this.isVirtual()) {
  175. this.save();
  176. }
  177. // Refetch options
  178. this.fetchPermissions();
  179. }
  180. public void setParents(String[] parentGroups, String worldName) {
  181. try {
  182. // Clean out existing records
  183. if (worldName != null) { // damn NULL
  184. this.backend.getSQL().prepAndBind("DELETE FROM `{permissions_inheritance}` WHERE `child` = ? AND `type` = ? AND `world` = ?", this.getName(), this.type.ordinal(), worldName).execute();
  185. } else {
  186. this.backend.getSQL().prepAndBind("DELETE FROM `{permissions_inheritance}` WHERE `child` = ? AND `type` = ? AND IFNULL(`world`, 1)", this.getName(), this.type.ordinal()).execute();
  187. }
  188. PreparedStatement statement = this.backend.getSQL().prepAndBind("INSERT INTO `{permissions_inheritance}` (`child`, `parent`, `type`, `world`) VALUES (?, ?, ?, ?)", this.getName(), "toset", this.type.ordinal(), worldName);
  189. for (String group : parentGroups) {
  190. if (group == null || group.isEmpty()) {
  191. continue;
  192. }
  193. statement.setString(2, group);
  194. statement.addBatch();
  195. }
  196. statement.executeBatch();
  197. } catch (SQLException e) {
  198. throw new RuntimeException(e);
  199. }
  200. if (this.isVirtual()) {
  201. this.save();
  202. }
  203. //reload inherirance
  204. this.parents = null;
  205. this.fetchInheritance();
  206. }
  207. @Override
  208. public Map<String, String> getOptions(String world) {
  209. Map<String, String> options = world == null ? this.commonOptions : this.worldsOptions.get(world);
  210. return options != null ? options : new HashMap<String, String>();
  211. }
  212. @Override
  213. public Map<String, String[]> getAllPermissions() {
  214. Map<String, String[]> allPermissions = new HashMap<String, String[]>();
  215. allPermissions.put(null, this.commonPermissions.toArray(new String[0]));
  216. for (Map.Entry<String, List<String>> entry : this.worldsPermissions.entrySet()) {
  217. allPermissions.put(entry.getKey(), entry.getValue().toArray(new String[0]));
  218. }
  219. return allPermissions;
  220. }
  221. @Override
  222. public Map<String, Map<String, String>> getAllOptions() {
  223. Map<String, Map<String, String>> allOptions = new HashMap<String, Map<String, String>>();
  224. allOptions.put(null, this.commonOptions);
  225. for (Map.Entry<String, Map<String, String>> entry : this.worldsOptions.entrySet()) {
  226. allOptions.put(entry.getKey(), entry.getValue());
  227. }
  228. return allOptions;
  229. }
  230. @Override
  231. public void setPermissions(String[] permissions, String world) {
  232. if (world == null) {
  233. world = "";
  234. }
  235. try {
  236. this.backend.getSQL().prepAndBind("DELETE FROM `{permissions}` WHERE `name` = ? AND `type` = ? AND `world` = ? AND `value` = ''", this.getName(), this.type.ordinal(), world).execute();
  237. PreparedStatement statement = this.backend.getSQL().prepAndBind("INSERT INTO `{permissions}` (`name`, `permission`, `value`, `world`, `type`) VALUES (?, ?, '', ?, ?)", this.getName(), "toset", world, this.type.ordinal());
  238. for (int i = permissions.length - 1; i >= 0; i--) { // insert in reverse order
  239. statement.setString(2, permissions[i]);
  240. statement.addBatch();
  241. }
  242. statement.executeBatch();
  243. } catch (SQLException e) {
  244. throw new RuntimeException(e);
  245. }
  246. if (this.isVirtual()) {
  247. this.save();
  248. }
  249. this.fetchPermissions();
  250. }
  251. @Override
  252. public void save() {
  253. this.updateInfo();
  254. }
  255. @Override
  256. public void remove() {
  257. try {
  258. // clear inheritance info
  259. this.backend.getSQL().prepAndBind("DELETE FROM `{permissions_inheritance}` WHERE `child` = ? AND `type` = ?", this.getName(), this.type.ordinal()).execute();
  260. // clear permissions
  261. this.backend.getSQL().prepAndBind("DELETE FROM `{permissions}` WHERE `name` = ? AND `type` = ?", this.getName(), this.type.ordinal()).execute();
  262. // clear info
  263. this.backend.getSQL().prepAndBind("DELETE FROM `{permissions_entity}` WHERE `name` = ? AND `type` = ?", this.getName(), this.type.ordinal()).execute();
  264. } catch (SQLException e) {
  265. throw new RuntimeException(e);
  266. }
  267. this.virtual = true;
  268. this.commonOptions.clear();
  269. this.commonPermissions.clear();
  270. this.worldsOptions.clear();
  271. this.worldsPermissions.clear();
  272. this.parents.clear();
  273. }
  274. protected void updateInfo() {
  275. String sql;
  276. if (this.isVirtual()) { // This section are suspicious, here was problem which are resolved mysticaly. Keep eye on it.
  277. sql = "INSERT INTO `{permissions_entity}` (`prefix`, `suffix`, `name`, `type`) VALUES (?, ?, ?, ?)";
  278. } else {
  279. sql = "UPDATE `{permissions_entity}` SET `prefix` = ?, `suffix` = ? WHERE `name` = ? AND `type` = ?";
  280. }
  281. try {
  282. this.backend.getSQL().prepAndBind(sql, this.prefix, this.suffix, this.getName(), this.type.ordinal()).execute();
  283. } catch (SQLException e) {
  284. if (this.isVirtual()) {
  285. this.virtual = false;
  286. this.updateInfo(); // try again
  287. }
  288. throw new RuntimeException(e);
  289. }
  290. this.virtual = false;
  291. }
  292. protected final void fetchPermissions() {
  293. this.worldsOptions = new HashMap<String, Map<String, String>>();
  294. this.worldsPermissions = new HashMap<String, List<String>>();
  295. this.commonOptions = new HashMap<String, String>();
  296. this.commonPermissions = new LinkedList<String>();
  297. try {
  298. ResultSet results = this.backend.getSQL().prepAndBind("SELECT `permission`, `world`, `value` FROM `{permissions}` WHERE `name` = ? AND `type` = ? ORDER BY `id` DESC", this.getName(), this.type.ordinal()).executeQuery();
  299. while (results.next()) {
  300. String permission = results.getString("permission").trim();
  301. String world = results.getString("world").trim();
  302. String value = results.getString("value");
  303. // @TODO: to this in more optimal way
  304. if (value.isEmpty()) {
  305. if (!world.isEmpty()) {
  306. List<String> worldPermissions = this.worldsPermissions.get(world);
  307. if (worldPermissions == null) {
  308. worldPermissions = new LinkedList<String>();
  309. this.worldsPermissions.put(world, worldPermissions);
  310. }
  311. worldPermissions.add(permission);
  312. } else {
  313. this.commonPermissions.add(permission);
  314. }
  315. } else {
  316. if (!world.isEmpty()) {
  317. Map<String, String> worldOptions = this.worldsOptions.get(world);
  318. if (worldOptions == null) {
  319. worldOptions = new HashMap<String, String>();
  320. worldsOptions.put(world, worldOptions);
  321. }
  322. worldOptions.put(permission, value);
  323. } else {
  324. commonOptions.put(permission, value);
  325. }
  326. }
  327. }
  328. } catch (SQLException e) {
  329. throw new RuntimeException(e);
  330. }
  331. }
  332. protected final void fetchInheritance() {
  333. try {
  334. this.parents = new HashMap<String, Set<String>>();
  335. ResultSet results = this.backend.getSQL().prepAndBind("SELECT `parent`, `world` FROM `{permissions_inheritance}` WHERE `child` = ? AND `type` = ? ORDER BY `id` DESC", this.getName(), this.type.ordinal()).executeQuery();
  336. while (results.next()) {
  337. String parentName = results.getString(1);
  338. String worldName = results.getString(2);
  339. if (!this.parents.containsKey(worldName)) {
  340. this.parents.put(worldName, new HashSet<String>());
  341. }
  342. this.parents.get(worldName).add(parentName);
  343. }
  344. } catch (SQLException e) {
  345. throw new RuntimeException(e);
  346. }
  347. }
  348. protected final void fetchInfo() {
  349. try {
  350. ResultSet result = this.backend.getSQL().prepAndBind("SELECT `name`, `prefix`, `suffix` FROM `{permissions_entity}` WHERE `name` = ? AND `type` = ? LIMIT 1", this.getName(), this.type.ordinal()).executeQuery();
  351. if (result.next()) {
  352. this.prefix = result.getString("prefix");
  353. this.suffix = result.getString("suffix");
  354. // For teh case-insensetivity
  355. this.setName(result.getString("name"));
  356. this.virtual = false;
  357. } else {
  358. this.prefix = "";
  359. this.suffix = "";
  360. this.virtual = true;
  361. }
  362. } catch (SQLException e) {
  363. throw new RuntimeException(e);
  364. }
  365. }
  366. }