/* * PermissionsEx - Permissions plugin for Bukkit * Copyright (C) 2011 t3hk0d3 http://www.tehkode.ru * * 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 2 * of the License, or (at your option) any later version. * * 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; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package pex.permissions.backends.sql; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import pex.permissions.PermissionEntity; import pex.permissions.PermissionManager; /** * * @author code */ public class SQLEntity extends PermissionEntity { public enum Type { GROUP, USER } protected SQLConnection db; protected Map<String, List<String>> worldsPermissions = null; protected Map<String, Map<String, String>> worldsOptions = null; protected List<String> commonPermissions = null; protected Map<String, String> commonOptions = null; protected Map<String, Set<String>> parents = null; protected Type type; protected String prefix; protected String suffix; public SQLEntity(String name, PermissionManager manager, SQLEntity.Type type, SQLConnection db) { super(name, manager); this.db = db; this.type = type; fetchInfo(); fetchPermissions(); fetchInheritance(); } public static String[] getEntitiesNames(SQLConnection sql, Type type, boolean defaultOnly) { try { List<String> entities = new LinkedList<String>(); ResultSet result = sql.select("SELECT name FROM `permissions_entity` WHERE `type` = ? " + (defaultOnly ? " AND `default` = 1" : ""), type.ordinal()); while (result.next()) { entities.add(result.getString("name")); } result.close(); return entities.toArray(new String[0]); } catch (SQLException e) { throw new RuntimeException(e); } } @Override public String[] getWorlds() { Set<String> worlds = new HashSet<String>(); worlds.addAll(worldsOptions.keySet()); worlds.addAll(worldsPermissions.keySet()); worlds.addAll(parents.keySet()); return worlds.toArray(new String[0]); } @Override public String getPrefix(String worldName) { return worldName == null || worldName.isEmpty() ? prefix : this.getOption("prefix", worldName); } @Override public String getSuffix(String worldName) { return worldName == null || worldName.isEmpty() ? suffix : this.getOption("suffix", worldName); } @Override public void setPrefix(String prefix, String worldName) { if (worldName == null || worldName.isEmpty()) { this.prefix = prefix; updateInfo(); } else { this.setOption("prefix", prefix, worldName); } } @Override public void setSuffix(String suffix, String worldName) { if (worldName == null || worldName.isEmpty()) { this.suffix = suffix; updateInfo(); } else { this.setOption("suffix", suffix, worldName); } } public String[] getParentNames(String worldName) { if (parents == null) { fetchInheritance(); } if (parents.containsKey(worldName)) { return parents.get(worldName).toArray(new String[0]); } return new String[0]; } @Override public String[] getPermissions(String world) { List<String> permissions = new LinkedList<String>(); if (commonPermissions == null) { fetchPermissions(); } if (world != null && !world.isEmpty()) { List<String> worldPermissions = worldsPermissions.get(world); if (worldPermissions != null) { permissions.addAll(worldPermissions); } } else { permissions = commonPermissions; } return permissions.toArray(new String[0]); } @Override public String getOption(String option, String world, String defaultValue) { if (world != null && !world.isEmpty() && worldsOptions.containsKey(world)) { if (worldsOptions.get(world).containsKey(option)) { return worldsOptions.get(world).get(option); } } if ((world == null || world.isEmpty()) && commonOptions.containsKey(option)) { return commonOptions.get(option); } return defaultValue; } @Override public void setOption(String option, String value, String world) { if (option == null || option.isEmpty()) { return; } if (world == null) { world = ""; } if (value == null || value.isEmpty()) { try { db.executeUpdate("DELETE FROM `permissions` WHERE `name` = ? AND `permission` = ? AND `type` = ? AND `world` = ?", getName(), option, type.ordinal(), world); } catch (SQLException e) { throw new RuntimeException(e); } if (!world.isEmpty() && worldsOptions.containsKey(world)) { worldsOptions.get(world).remove(option); } else { commonOptions.remove(option); } return; } Boolean newOption = true; if (commonOptions == null) { fetchPermissions(); } if (!world.isEmpty() && worldsOptions.containsKey(world) && worldsOptions.get(world).containsKey(option)) { newOption = false; } else if (world.isEmpty() && commonOptions.containsKey(option)) { newOption = false; } try { if (newOption) { db.executeUpdate("INSERT INTO `permissions` (`name`, `permission`, `value`, `world`, `type`) VALUES (?, ?, ?, ?, ?)", getName(), option, value, world, type.ordinal()); } else { db.executeUpdate("UPDATE `permissions` SET `value` = ? WHERE `name` = ? AND `type` = ? AND `permission` = ?", value, getName(), type.ordinal(), option); } } catch (SQLException e) { throw new RuntimeException(e); } if (isVirtual()) { save(); } // Refetch options fetchPermissions(); } public void setParents(String[] parentGroups, String worldName) { try { // Clean out existing records if (worldName != null) { // damn NULL db.executeUpdate("DELETE FROM `permissions_inheritance` WHERE `child` = ? AND `type` = ? AND `world` = ?", getName(), type.ordinal(), worldName); } else { db.executeUpdate("DELETE FROM `permissions_inheritance` WHERE `child` = ? AND `type` = ? AND IFNULL(`world`, 1)", getName(), type.ordinal()); } List<Object[]> rows = new LinkedList<Object[]>(); for (String group : parentGroups) { if (group == null || group.isEmpty()) { continue; } rows.add(new Object[] { getName(), group, type.ordinal(), worldName }); } db.insert("permissions_inheritance", new String[] { "child", "parent", "type", "world" }, rows); } catch (SQLException e) { throw new RuntimeException(e); } if (isVirtual()) { save(); } // reload inherirance parents = null; fetchInheritance(); } @Override public Map<String, String> getOptions(String world) { Map<String, String> options = world == null ? commonOptions : worldsOptions.get(world); return options != null ? options : new HashMap<String, String>(); } @Override public Map<String, String[]> getAllPermissions() { Map<String, String[]> allPermissions = new HashMap<String, String[]>(); allPermissions.put(null, commonPermissions.toArray(new String[0])); for (Map.Entry<String, List<String>> entry : worldsPermissions.entrySet()) { allPermissions.put(entry.getKey(), entry.getValue().toArray(new String[0])); } return allPermissions; } @Override public Map<String, Map<String, String>> getAllOptions() { Map<String, Map<String, String>> allOptions = new HashMap<String, Map<String, String>>(); allOptions.put(null, commonOptions); for (Map.Entry<String, Map<String, String>> entry : worldsOptions.entrySet()) { allOptions.put(entry.getKey(), entry.getValue()); } return allOptions; } @Override public void setPermissions(String[] permissions, String world) { if (world == null) { world = ""; } try { db.executeUpdate("DELETE FROM `permissions` WHERE `name` = ? AND `type` = ? AND `world` = ? AND `value` = ''", getName(), type.ordinal(), world); for (int i = permissions.length - 1; i >= 0; i--) { // insert in // reverse order db.executeUpdate("INSERT INTO `permissions` (`name`, `permission`, `value`, `world`, `type`) VALUES (?, ?, '', ?, ?)", getName(), permissions[i], world, type.ordinal()); } } catch (SQLException e) { throw new RuntimeException(e); } if (isVirtual()) { save(); } fetchPermissions(); } @Override public void save() { updateInfo(); } @Override public void remove() { try { // clear inheritance info db.executeUpdate("DELETE FROM `permissions_inheritance` WHERE `child` = ? AND `type` = ?", getName(), type.ordinal()); // clear permissions db.executeUpdate("DELETE FROM `permissions` WHERE `name` = ? AND `type` = ?", getName(), type.ordinal()); // clear info db.executeUpdate("DELETE FROM `permissions_entity` WHERE `name` = ? AND `type` = ?", getName(), type.ordinal()); } catch (SQLException e) { throw new RuntimeException(e); } virtual = true; commonOptions.clear(); commonPermissions.clear(); worldsOptions.clear(); worldsPermissions.clear(); parents.clear(); } protected void updateInfo() { String sql; if (isVirtual()) { // This section are suspicious, here was problem // which are resolved mysticaly. Keep eye on it. sql = "INSERT INTO `permissions_entity` (`prefix`, `suffix`, `name`, `type`) VALUES (?, ?, ?, ?)"; } else { sql = "UPDATE `permissions_entity` SET `prefix` = ?, `suffix` = ? WHERE `name` = ? AND `type` = ?"; } try { db.executeUpdate(sql, prefix, suffix, getName(), type.ordinal()); } catch (SQLException e) { if (isVirtual()) { virtual = false; updateInfo(); // try again } throw new RuntimeException(e); } virtual = false; } protected final void fetchPermissions() { worldsOptions = new HashMap<String, Map<String, String>>(); worldsPermissions = new HashMap<String, List<String>>(); commonOptions = new HashMap<String, String>(); commonPermissions = new LinkedList<String>(); try { ResultSet results = db.select("SELECT `permission`, `world`, `value` FROM `permissions` WHERE `name` = ? AND `type` = ? ORDER BY `id` DESC", getName(), type.ordinal()); while (results.next()) { String permission = results.getString("permission").trim(); String world = results.getString("world").trim(); String value = results.getString("value"); // @TODO: to this in more optimal way if (value.isEmpty()) { if (!world.isEmpty()) { List<String> worldPermissions = worldsPermissions.get(world); if (worldPermissions == null) { worldPermissions = new LinkedList<String>(); worldsPermissions.put(world, worldPermissions); } worldPermissions.add(permission); } else { commonPermissions.add(permission); } } else { if (!world.isEmpty()) { Map<String, String> worldOptions = worldsOptions.get(world); if (worldOptions == null) { worldOptions = new HashMap<String, String>(); worldsOptions.put(world, worldOptions); } worldOptions.put(permission, value); } else { commonOptions.put(permission, value); } } } } catch (SQLException e) { throw new RuntimeException(e); } } protected final void fetchInheritance() { try { parents = new HashMap<String, Set<String>>(); ResultSet results = db.select("SELECT `parent`, `world` FROM `permissions_inheritance` WHERE `child` = ? AND `type` = ? ORDER BY `id` DESC", getName(), type.ordinal()); while (results.next()) { String parentName = results.getString(1); String worldName = results.getString(2); if (!parents.containsKey(worldName)) { parents.put(worldName, new HashSet<String>()); } parents.get(worldName).add(parentName); } } catch (SQLException e) { throw new RuntimeException(e); } } protected final void fetchInfo() { try { ResultSet result = db.select("SELECT `name`, `prefix`, `suffix` FROM `permissions_entity` WHERE `name` = ? AND `type` = ? LIMIT 1", getName(), type.ordinal()); if (result.next()) { prefix = result.getString("prefix"); suffix = result.getString("suffix"); // For teh case-insensetivity setName(result.getString("name")); virtual = false; } else { prefix = ""; suffix = ""; virtual = true; } } catch (SQLException e) { throw new RuntimeException(e); } } }