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 }