001 package org.bukkit.permissions; 002 003 import java.util.ArrayList; 004 import java.util.LinkedHashMap; 005 import java.util.List; 006 import java.util.Map; 007 import java.util.Set; 008 import java.util.logging.Level; 009 010 import org.apache.commons.lang.Validate; 011 import org.bukkit.Bukkit; 012 import org.bukkit.plugin.PluginManager; 013 014 /** 015 * Represents a unique permission that may be attached to a {@link 016 * Permissible} 017 */ 018 public class Permission { 019 public static final PermissionDefault DEFAULT_PERMISSION = PermissionDefault.OP; 020 021 private final String name; 022 private final Map<String, Boolean> children = new LinkedHashMap<String, Boolean>(); 023 private PermissionDefault defaultValue = DEFAULT_PERMISSION; 024 private String description; 025 026 public Permission(String name) { 027 this(name, null, null, null); 028 } 029 030 public Permission(String name, String description) { 031 this(name, description, null, null); 032 } 033 034 public Permission(String name, PermissionDefault defaultValue) { 035 this(name, null, defaultValue, null); 036 } 037 038 public Permission(String name, String description, PermissionDefault defaultValue) { 039 this(name, description, defaultValue, null); 040 } 041 042 public Permission(String name, Map<String, Boolean> children) { 043 this(name, null, null, children); 044 } 045 046 public Permission(String name, String description, Map<String, Boolean> children) { 047 this(name, description, null, children); 048 } 049 050 public Permission(String name, PermissionDefault defaultValue, Map<String, Boolean> children) { 051 this(name, null, defaultValue, children); 052 } 053 054 public Permission(String name, String description, PermissionDefault defaultValue, Map<String, Boolean> children) { 055 this.name = name; 056 this.description = (description == null) ? "" : description; 057 058 if (defaultValue != null) { 059 this.defaultValue = defaultValue; 060 } 061 062 if (children != null) { 063 this.children.putAll(children); 064 } 065 066 recalculatePermissibles(); 067 } 068 069 /** 070 * Returns the unique fully qualified name of this Permission 071 * 072 * @return Fully qualified name 073 */ 074 public String getName() { 075 return name; 076 } 077 078 /** 079 * Gets the children of this permission. 080 * <p> 081 * If you change this map in any form, you must call {@link 082 * #recalculatePermissibles()} to recalculate all {@link Permissible}s 083 * 084 * @return Permission children 085 */ 086 public Map<String, Boolean> getChildren() { 087 return children; 088 } 089 090 /** 091 * Gets the default value of this permission. 092 * 093 * @return Default value of this permission. 094 */ 095 public PermissionDefault getDefault() { 096 return defaultValue; 097 } 098 099 /** 100 * Sets the default value of this permission. 101 * <p> 102 * This will not be saved to disk, and is a temporary operation until the 103 * server reloads permissions. Changing this default will cause all {@link 104 * Permissible}s that contain this permission to recalculate their 105 * permissions 106 * 107 * @param value The new default to set 108 */ 109 public void setDefault(PermissionDefault value) { 110 if (defaultValue == null) { 111 throw new IllegalArgumentException("Default value cannot be null"); 112 } 113 114 defaultValue = value; 115 recalculatePermissibles(); 116 } 117 118 /** 119 * Gets a brief description of this permission, if set 120 * 121 * @return Brief description of this permission 122 */ 123 public String getDescription() { 124 return description; 125 } 126 127 /** 128 * Sets the description of this permission. 129 * <p> 130 * This will not be saved to disk, and is a temporary operation until the 131 * server reloads permissions. 132 * 133 * @param value The new description to set 134 */ 135 public void setDescription(String value) { 136 if (value == null) { 137 description = ""; 138 } else { 139 description = value; 140 } 141 } 142 143 /** 144 * Gets a set containing every {@link Permissible} that has this 145 * permission. 146 * <p> 147 * This set cannot be modified. 148 * 149 * @return Set containing permissibles with this permission 150 */ 151 public Set<Permissible> getPermissibles() { 152 return Bukkit.getServer().getPluginManager().getPermissionSubscriptions(name); 153 } 154 155 /** 156 * Recalculates all {@link Permissible}s that contain this permission. 157 * <p> 158 * This should be called after modifying the children, and is 159 * automatically called after modifying the default value 160 */ 161 public void recalculatePermissibles() { 162 Set<Permissible> perms = getPermissibles(); 163 164 Bukkit.getServer().getPluginManager().recalculatePermissionDefaults(this); 165 166 for (Permissible p : perms) { 167 p.recalculatePermissions(); 168 } 169 } 170 171 /** 172 * Adds this permission to the specified parent permission. 173 * <p> 174 * If the parent permission does not exist, it will be created and 175 * registered. 176 * 177 * @param name Name of the parent permission 178 * @param value The value to set this permission to 179 * @return Parent permission it created or loaded 180 */ 181 public Permission addParent(String name, boolean value) { 182 PluginManager pm = Bukkit.getServer().getPluginManager(); 183 String lname = name.toLowerCase(); 184 185 Permission perm = pm.getPermission(lname); 186 187 if (perm == null) { 188 perm = new Permission(lname); 189 pm.addPermission(perm); 190 } 191 192 addParent(perm, value); 193 194 return perm; 195 } 196 197 /** 198 * Adds this permission to the specified parent permission. 199 * 200 * @param perm Parent permission to register with 201 * @param value The value to set this permission to 202 */ 203 public void addParent(Permission perm, boolean value) { 204 perm.getChildren().put(getName(), value); 205 perm.recalculatePermissibles(); 206 } 207 208 /** 209 * Loads a list of Permissions from a map of data, usually used from 210 * retrieval from a yaml file. 211 * <p> 212 * The data may contain a list of name:data, where the data contains the 213 * following keys: 214 * <ul> 215 * <li>default: Boolean true or false. If not specified, false. 216 * <li>children: Map<String, Boolean> of child permissions. If not 217 * specified, empty list. 218 * <li>description: Short string containing a very small description of 219 * this description. If not specified, empty string. 220 * </ul> 221 * 222 * @param data Map of permissions 223 * @param error An error message to show if a permission is invalid. 224 * @param def Default permission value to use if missing 225 * @return Permission object 226 */ 227 public static List<Permission> loadPermissions(Map<?, ?> data, String error, PermissionDefault def) { 228 List<Permission> result = new ArrayList<Permission>(); 229 230 for (Map.Entry<?, ?> entry : data.entrySet()) { 231 try { 232 result.add(Permission.loadPermission(entry.getKey().toString(), (Map<?, ?>) entry.getValue(), def, result)); 233 } catch (Throwable ex) { 234 Bukkit.getServer().getLogger().log(Level.SEVERE, String.format(error, entry.getKey()), ex); 235 } 236 } 237 238 return result; 239 } 240 241 /** 242 * Loads a Permission from a map of data, usually used from retrieval from 243 * a yaml file. 244 * <p> 245 * The data may contain the following keys: 246 * <ul> 247 * <li>default: Boolean true or false. If not specified, false. 248 * <li>children: Map<String, Boolean> of child permissions. If not 249 * specified, empty list. 250 * <li>description: Short string containing a very small description of 251 * this description. If not specified, empty string. 252 * 253 * @param name Name of the permission 254 * @param data Map of keys 255 * @return Permission object 256 */ 257 public static Permission loadPermission(String name, Map<String, Object> data) { 258 return loadPermission(name, data, DEFAULT_PERMISSION, null); 259 } 260 261 /** 262 * Loads a Permission from a map of data, usually used from retrieval from 263 * a yaml file. 264 * <p> 265 * The data may contain the following keys: 266 * <ul> 267 * <li>default: Boolean true or false. If not specified, false. 268 * <li>children: Map<String, Boolean> of child permissions. If not 269 * specified, empty list. 270 * <li>description: Short string containing a very small description of 271 * this description. If not specified, empty string. 272 * </ul> 273 * 274 * @param name Name of the permission 275 * @param data Map of keys 276 * @param def Default permission value to use if not set 277 * @param output A list to append any created child-Permissions to, may be null 278 * @return Permission object 279 */ 280 public static Permission loadPermission(String name, Map<?, ?> data, PermissionDefault def, List<Permission> output) { 281 Validate.notNull(name, "Name cannot be null"); 282 Validate.notNull(data, "Data cannot be null"); 283 284 String desc = null; 285 Map<String, Boolean> children = null; 286 287 if (data.get("default") != null) { 288 PermissionDefault value = PermissionDefault.getByName(data.get("default").toString()); 289 if (value != null) { 290 def = value; 291 } else { 292 throw new IllegalArgumentException("'default' key contained unknown value"); 293 } 294 } 295 296 if (data.get("children") != null) { 297 Object childrenNode = data.get("children"); 298 if (childrenNode instanceof Iterable) { 299 children = new LinkedHashMap<String, Boolean>(); 300 for (Object child : (Iterable<?>) childrenNode) { 301 if (child != null) { 302 children.put(child.toString(), Boolean.TRUE); 303 } 304 } 305 } else if (childrenNode instanceof Map) { 306 children = extractChildren((Map<?,?>) childrenNode, name, def, output); 307 } else { 308 throw new IllegalArgumentException("'children' key is of wrong type"); 309 } 310 } 311 312 if (data.get("description") != null) { 313 desc = data.get("description").toString(); 314 } 315 316 return new Permission(name, desc, def, children); 317 } 318 319 private static Map<String, Boolean> extractChildren(Map<?, ?> input, String name, PermissionDefault def, List<Permission> output) { 320 Map<String, Boolean> children = new LinkedHashMap<String, Boolean>(); 321 322 for (Map.Entry<?, ?> entry : input.entrySet()) { 323 if ((entry.getValue() instanceof Boolean)) { 324 children.put(entry.getKey().toString(), (Boolean) entry.getValue()); 325 } else if ((entry.getValue() instanceof Map)) { 326 try { 327 Permission perm = loadPermission(entry.getKey().toString(), (Map<?, ?>) entry.getValue(), def, output); 328 children.put(perm.getName(), Boolean.TRUE); 329 330 if (output != null) { 331 output.add(perm); 332 } 333 } catch (Throwable ex) { 334 throw new IllegalArgumentException("Permission node '" + entry.getKey().toString() + "' in child of " + name + " is invalid", ex); 335 } 336 } else { 337 throw new IllegalArgumentException("Child '" + entry.getKey().toString() + "' contains invalid value"); 338 } 339 } 340 341 return children; 342 } 343 }