Newer
Older
ultramine_bukkit / src / main / java / org / bukkit / permissions / Permission.java
@vlad20012 vlad20012 on 24 Feb 2017 10 KB initial
package org.bukkit.permissions;

import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.plugin.PluginManager;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;

/**
 * Represents a unique permission that may be attached to a {@link
 * Permissible}
 */
public class Permission
{
	public static final PermissionDefault DEFAULT_PERMISSION = PermissionDefault.OP;

	private final String name;
	private final Map<String, Boolean> children = new LinkedHashMap<String, Boolean>();
	private PermissionDefault defaultValue = DEFAULT_PERMISSION;
	private String description;

	public Permission(String name)
	{
		this(name, null, null, null);
	}

	public Permission(String name, String description)
	{
		this(name, description, null, null);
	}

	public Permission(String name, PermissionDefault defaultValue)
	{
		this(name, null, defaultValue, null);
	}

	public Permission(String name, String description, PermissionDefault defaultValue)
	{
		this(name, description, defaultValue, null);
	}

	public Permission(String name, Map<String, Boolean> children)
	{
		this(name, null, null, children);
	}

	public Permission(String name, String description, Map<String, Boolean> children)
	{
		this(name, description, null, children);
	}

	public Permission(String name, PermissionDefault defaultValue, Map<String, Boolean> children)
	{
		this(name, null, defaultValue, children);
	}

	public Permission(String name, String description, PermissionDefault defaultValue, Map<String, Boolean> children)
	{
		this.name = name;
		this.description = (description == null) ? "" : description;

		if(defaultValue != null)
		{
			this.defaultValue = defaultValue;
		}

		if(children != null)
		{
			this.children.putAll(children);
		}

		recalculatePermissibles();
	}

	/**
	 * Returns the unique fully qualified name of this Permission
	 *
	 * @return Fully qualified name
	 */
	public String getName()
	{
		return name;
	}

	/**
	 * Gets the children of this permission.
	 * <p>
	 * If you change this map in any form, you must call {@link
	 * #recalculatePermissibles()} to recalculate all {@link Permissible}s
	 *
	 * @return Permission children
	 */
	public Map<String, Boolean> getChildren()
	{
		return children;
	}

	/**
	 * Gets the default value of this permission.
	 *
	 * @return Default value of this permission.
	 */
	public PermissionDefault getDefault()
	{
		return defaultValue;
	}

	/**
	 * Sets the default value of this permission.
	 * <p>
	 * This will not be saved to disk, and is a temporary operation until the
	 * server reloads permissions. Changing this default will cause all {@link
	 * Permissible}s that contain this permission to recalculate their
	 * permissions
	 *
	 * @param value The new default to set
	 */
	public void setDefault(PermissionDefault value)
	{
		if(defaultValue == null)
		{
			throw new IllegalArgumentException("Default value cannot be null");
		}

		defaultValue = value;
		recalculatePermissibles();
	}

	/**
	 * Gets a brief description of this permission, if set
	 *
	 * @return Brief description of this permission
	 */
	public String getDescription()
	{
		return description;
	}

	/**
	 * Sets the description of this permission.
	 * <p>
	 * This will not be saved to disk, and is a temporary operation until the
	 * server reloads permissions.
	 *
	 * @param value The new description to set
	 */
	public void setDescription(String value)
	{
		if(value == null)
		{
			description = "";
		}
		else
		{
			description = value;
		}
	}

	/**
	 * Gets a set containing every {@link Permissible} that has this
	 * permission.
	 * <p>
	 * This set cannot be modified.
	 *
	 * @return Set containing permissibles with this permission
	 */
	public Set<Permissible> getPermissibles()
	{
		return Bukkit.getServer().getPluginManager().getPermissionSubscriptions(name);
	}

	/**
	 * Recalculates all {@link Permissible}s that contain this permission.
	 * <p>
	 * This should be called after modifying the children, and is
	 * automatically called after modifying the default value
	 */
	public void recalculatePermissibles()
	{
		Set<Permissible> perms = getPermissibles();

		Bukkit.getServer().getPluginManager().recalculatePermissionDefaults(this);

		for(Permissible p : perms)
		{
			p.recalculatePermissions();
		}
	}

	/**
	 * Adds this permission to the specified parent permission.
	 * <p>
	 * If the parent permission does not exist, it will be created and
	 * registered.
	 *
	 * @param name  Name of the parent permission
	 * @param value The value to set this permission to
	 * @return Parent permission it created or loaded
	 */
	public Permission addParent(String name, boolean value)
	{
		PluginManager pm = Bukkit.getServer().getPluginManager();
		String lname = name.toLowerCase();

		Permission perm = pm.getPermission(lname);

		if(perm == null)
		{
			perm = new Permission(lname);
			pm.addPermission(perm);
		}

		addParent(perm, value);

		return perm;
	}

	/**
	 * Adds this permission to the specified parent permission.
	 *
	 * @param perm  Parent permission to register with
	 * @param value The value to set this permission to
	 */
	public void addParent(Permission perm, boolean value)
	{
		perm.getChildren().put(getName(), value);
		perm.recalculatePermissibles();
	}

	/**
	 * Loads a list of Permissions from a map of data, usually used from
	 * retrieval from a yaml file.
	 * <p>
	 * The data may contain a list of name:data, where the data contains the
	 * following keys:
	 * <ul>
	 * <li>default: Boolean true or false. If not specified, false.
	 * <li>children: Map<String, Boolean> of child permissions. If not
	 * specified, empty list.
	 * <li>description: Short string containing a very small description of
	 * this description. If not specified, empty string.
	 * </ul>
	 *
	 * @param data  Map of permissions
	 * @param error An error message to show if a permission is invalid.
	 * @param def   Default permission value to use if missing
	 * @return Permission object
	 */
	public static List<Permission> loadPermissions(Map<?, ?> data, String error, PermissionDefault def)
	{
		List<Permission> result = new ArrayList<Permission>();

		for(Map.Entry<?, ?> entry : data.entrySet())
		{
			try
			{
				result.add(Permission.loadPermission(entry.getKey().toString(), (Map<?, ?>) entry.getValue(), def, result));
			} catch(Throwable ex)
			{
				Bukkit.getServer().getLogger().log(Level.SEVERE, String.format(error, entry.getKey()), ex);
			}
		}

		return result;
	}

	/**
	 * Loads a Permission from a map of data, usually used from retrieval from
	 * a yaml file.
	 * <p>
	 * The data may contain the following keys:
	 * <ul>
	 * <li>default: Boolean true or false. If not specified, false.
	 * <li>children: Map<String, Boolean> of child permissions. If not
	 * specified, empty list.
	 * <li>description: Short string containing a very small description of
	 * this description. If not specified, empty string.
	 *
	 * @param name Name of the permission
	 * @param data Map of keys
	 * @return Permission object
	 */
	public static Permission loadPermission(String name, Map<String, Object> data)
	{
		return loadPermission(name, data, DEFAULT_PERMISSION, null);
	}

	/**
	 * Loads a Permission from a map of data, usually used from retrieval from
	 * a yaml file.
	 * <p>
	 * The data may contain the following keys:
	 * <ul>
	 * <li>default: Boolean true or false. If not specified, false.
	 * <li>children: Map<String, Boolean> of child permissions. If not
	 * specified, empty list.
	 * <li>description: Short string containing a very small description of
	 * this description. If not specified, empty string.
	 * </ul>
	 *
	 * @param name   Name of the permission
	 * @param data   Map of keys
	 * @param def    Default permission value to use if not set
	 * @param output A list to append any created child-Permissions to, may be null
	 * @return Permission object
	 */
	public static Permission loadPermission(String name, Map<?, ?> data, PermissionDefault def, List<Permission> output)
	{
		Validate.notNull(name, "Name cannot be null");
		Validate.notNull(data, "Data cannot be null");

		String desc = null;
		Map<String, Boolean> children = null;

		if(data.get("default") != null)
		{
			PermissionDefault value = PermissionDefault.getByName(data.get("default").toString());
			if(value != null)
			{
				def = value;
			}
			else
			{
				throw new IllegalArgumentException("'default' key contained unknown value");
			}
		}

		if(data.get("children") != null)
		{
			Object childrenNode = data.get("children");
			if(childrenNode instanceof Iterable)
			{
				children = new LinkedHashMap<String, Boolean>();
				for(Object child : (Iterable<?>) childrenNode)
				{
					if(child != null)
					{
						children.put(child.toString(), Boolean.TRUE);
					}
				}
			}
			else if(childrenNode instanceof Map)
			{
				children = extractChildren((Map<?, ?>) childrenNode, name, def, output);
			}
			else
			{
				throw new IllegalArgumentException("'children' key is of wrong type");
			}
		}

		if(data.get("description") != null)
		{
			desc = data.get("description").toString();
		}

		return new Permission(name, desc, def, children);
	}

	private static Map<String, Boolean> extractChildren(Map<?, ?> input, String name, PermissionDefault def, List<Permission> output)
	{
		Map<String, Boolean> children = new LinkedHashMap<String, Boolean>();

		for(Map.Entry<?, ?> entry : input.entrySet())
		{
			if((entry.getValue() instanceof Boolean))
			{
				children.put(entry.getKey().toString(), (Boolean) entry.getValue());
			}
			else if((entry.getValue() instanceof Map))
			{
				try
				{
					Permission perm = loadPermission(entry.getKey().toString(), (Map<?, ?>) entry.getValue(), def, output);
					children.put(perm.getName(), Boolean.TRUE);

					if(output != null)
					{
						output.add(perm);
					}
				} catch(Throwable ex)
				{
					throw new IllegalArgumentException("Permission node '" + entry.getKey().toString() + "' in child of " + name + " is invalid", ex);
				}
			}
			else
			{
				throw new IllegalArgumentException("Child '" + entry.getKey().toString() + "' contains invalid value");
			}
		}

		return children;
	}
}