/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package pluginbase.permission; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * Represents a permissions that a Minecraft player may have. * * These should generally be defined as constants. * This class must be implemented for your specific Minecraft Server implementation. See {@link #verify(String)}. */ public abstract class Perm { /** Static initialization method. */ static void init() { } /** * Character used to separate permission namespaces. */ protected static final char SEPARATOR = '.'; private static final Map<String, Perm> ALL_PERM_MAP = new HashMap<String, Perm>(); private static final Map<String, Perm> ALL_CMD_PERM_MAP = new HashMap<String, Perm>(); /** * Retrieves the Perm that represents the top level all encompassing permission for your plugin. * * {@link pluginbase.permission.PermFactory#addToAll()} adds this as a parent to the new * Perm. * * @param clazz Your plugin class. * @return The "all" permission. */ public static Perm getAllPerm(final Class clazz) { return ALL_PERM_MAP.get(clazz.getName()); } /** * Retrieves the Perm that represents the top level all command encompassing permission for your plugin. * <p/> * {@link pluginbase.permission.PermFactory#commandPermission()} adds this as a parent * to the new Perm. * * @param clazz Your plugin class. * @return The "all" permission. */ public static Perm getCommandPerm(final Class clazz) { return ALL_CMD_PERM_MAP.get(clazz.getName()); } static String getBaseNameFromClass(final Class clazz) { final String possibleName = PermFactory.getPermissionName(clazz); if (possibleName != null) { return possibleName; } try { final Method m = clazz.getDeclaredMethod("getPermissionName"); m.setAccessible(true); try { return (String) m.invoke(null); } finally { m.setAccessible(false); } } catch (NoSuchMethodException ignore) { } catch (IllegalAccessException ignore) { } catch (InvocationTargetException ignore) { } catch (ClassCastException ignore) { } return clazz.getSimpleName(); } static void ensureParentPermsConfigured(final Class clazz) { if (!ALL_PERM_MAP.containsKey(clazz.getName())) { ALL_PERM_MAP.put(clazz.getName(), PermFactory.newUncheckedPerm(clazz, "*").usePluginName().build()); ALL_CMD_PERM_MAP.put(clazz.getName(), PermFactory.newUncheckedPerm(clazz, "cmd" + SEPARATOR + "*").usePluginName().addToAll().build()); } } /** * The permission's fully realized name. * * See: {@link #getName()} */ protected final String name; /** A description of this permission. */ protected final String description; /** A map of all child permissions and their default setting. */ protected final Map<String, Boolean> children; /** The default setting for this permission. */ protected final PermDefault permDefault; /** A map of all parent permissions and the default THIS permission will be set to if the player has the parent. */ protected final Map<String, Boolean> parents; /** Whether or not this permissions is allowed to be used without a specific node added. */ protected final boolean specificOnly; protected Perm(final Class declaringPluginClass, final String name, final String description, final Map<String, Boolean> children, final PermDefault permDefault, final Map<String, Boolean> parents, final boolean baseName, final boolean specificOnly) { if (baseName) { this.name = (getBaseNameFromClass(declaringPluginClass) + SEPARATOR + name).toLowerCase(); } else { this.name = name.toLowerCase(); } this.description = description; this.children = Collections.unmodifiableMap(children); this.permDefault = permDefault; this.parents = Collections.unmodifiableMap(parents); this.specificOnly = specificOnly; } /** * Gets the permission's fully realized name. * <p/> * This name represents the full namespace for the permission. Example: pluginbase.cmd.info. * <p/> * This method will also verify that the name given represents a valid permission. * * @return The permission's fully realized name. */ public final String getName() { if (specificOnly) { throw new UnsupportedOperationException("This Perm is only usable with an additional specific node!"); } verify(name); return name; } /** * Gets the permission's fully realized name with a specific sub node attachment. * <p/> * This name represents the full namespace for the permission. Example: multiverse.access.hellworld * <p/> * This method will also verify that the name given represents a valid permission. * * @param specific The specific sub-node to attach. * @return The permission's fully realized name with a specific sub node attachment. */ public final String getName(final String specific) { final String fullName = name + SEPARATOR + specific.toLowerCase(); verify(fullName); return fullName; } /** * Gets the permission's description. * * @return The permission's description. */ public final String getDescription() { return this.description; } /** * Gets a map of all child permissions and their default setting. * * @return An unmodifiable map of all child permissions. */ public final Map<String, Boolean> getChildren() { return this.children; } /** * Gets a map of all parent permissions and the default THIS permission will be set to if a player has them. * * @return An unmodifiable map of all parent permissions. */ public final Map<String, Boolean> getParents() { return this.parents; } /** * Gets the default setting for this permission. * * @return The default setting for this permission. */ public final PermDefault getPermDefault() { return this.permDefault; } /** * Checks if the sender has the permission in question. * <p/> * This method will also take any steps necessary to initialize the permission in Minecraft if required. * * @param permissible Permissible to check permission for. * @return True if sender has access to the permission. */ public final boolean hasPermission(final Permissible permissible) { return permissible.hasPermission(getName()); } /** * Checks if the sender has a specific sub-node of the permission in question. * <p/> * Sub-nodes are useful when you need permissions for non-constant things. * <p/> * For example, if you need to check if someone can access a specific world, you can have a * permission like 'multiverse.access' and use this method to check the name of the world which would * ultimately check if the player has access to 'multiverse.access.worldname'. * <p/> * This method will also take any steps necessary to initialize the specific permission in Minecraft if required. * * @param permissible Permissible to check permission for. * @param specific The specific sub-node to check for. * @return True if sender has access to the permission. */ public final boolean hasPermission(final Permissible permissible, final String specific) { return permissible.hasPermission(getName(specific)); } /** * This method will perform all the necessary steps required to initialize a permission in your Minecraft server * implementation. * <p/> * For example, in Bukkit, this will register any permission that is not already registered. * * @param name The name of the permission to verify. */ protected abstract void verify(final String name); }