Package net.canarymod.permissionsystem

Source Code of net.canarymod.permissionsystem.MultiworldPermissionProvider

package net.canarymod.permissionsystem;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import net.canarymod.Canary;
import net.canarymod.Translator;
import net.canarymod.backbone.PermissionDataAccess;
import net.canarymod.chat.Colors;
import net.canarymod.chat.MessageReceiver;
import net.canarymod.database.DataAccess;
import net.canarymod.database.Database;
import net.canarymod.database.exceptions.DatabaseReadException;

/**
* A PermissionProvider implementation based on PermissionNode objects,
* with multiworld support
*
* @author Chris (damagefilter)
*/
public class MultiworldPermissionProvider implements PermissionProvider {
    private ArrayList<PermissionNode> permissions;
    private HashMap<String, Boolean> permissionCache = new HashMap<String, Boolean>(35);
    private boolean isPlayerProvider;
    private String owner; // This can either be a player or group name
    private String world;
    private PermissionProvider parent = null;

    /**
     * Constructs a new PermissionProvider that's valid for the given world
     *
     * @param world
     */
    public MultiworldPermissionProvider(String world, boolean isPlayer, String owner) {
        this.world = world;
        permissions = new ArrayList<PermissionNode>();
        this.isPlayerProvider = isPlayer;
        this.owner = owner;
        if (world != null) {
            // We need a parent then
            if (isPlayer) {
                this.parent = Canary.permissionManager().getPlayerProvider(owner, null);
            }
            else {
                this.parent = Canary.permissionManager().getGroupsProvider(owner, null);
            }
        }
    }

    /**
     * Add a given permission to the permissions cache. The cache is limited and
     * will prune itself if it gets too big.
     *
     * @param path
     * @param value
     */
    private void addPermissionToCache(String path, boolean value) {
        if (permissionCache.size() > 35) {
            Iterator<Entry<String, Boolean>> it = permissionCache.entrySet().iterator();

            while (it.hasNext() && permissionCache.size() > 10) {
                it.next();
                it.remove();
            }
        }
        permissionCache.put(path, value);
    }

    /**
     * Check the permission cache if we have something already
     *
     * @param permission
     *
     * @return
     */
    private Boolean checkCached(String permission) {
        return permissionCache.get(permission);
    }

    @Override
    public ArrayList<PermissionNode> getChildNodes(PermissionNode node, ArrayList<PermissionNode> childs) {
        childs.add(node);
        if (node.hasChilds()) {
            for (String key : node.getChilds().keySet()) {
                getChildNodes(node.getChilds().get(key), childs);
            }
        }
        return childs;
    }

    /**
     * get a node that must be directly in the permissions list
     *
     * @param name
     *
     * @return
     */
    private PermissionNode getRootNode(String name) {
        for (PermissionNode n : permissions) {
            if (n.getName().equals(name) || n.isAsterisk()) {
                return n;
            }
        }
        return null;
    }

    /**
     * Resolve a path when adding new stuff
     *
     * @param path
     * @param value
     *
     * @return
     */
    private PermissionNode addPath(String[] path, boolean value) {
        PermissionNode node = null;
        boolean newPath = false;

        for (int current = 0; current < path.length; current++) {
            if (current == 0) {
                node = getRootNode(path[current]);
                if (node == null) {
                    newPath = true;
                    node = new PermissionNode(path[current], value);
                    permissions.add(node);
                    continue;
                }
            }
            if (newPath) {
                PermissionNode n = new PermissionNode(path[current], value);
                node.addChildNode(n);
                node = n;
            }
            else {
                if (current + 1 < path.length) {
                    if (node.hasChildNode(path[current + 1])) {
                        node = node.getChildNode(path[current + 1]);
                        if (current + 1 == (path.length - 1)) { // This is the end of the path. Update the value
                            node.setValue(value);
                        }
                    }
                    else {
                        PermissionNode n = new PermissionNode(path[current + 1], value);
                        node.addChildNode(n);
                        node = n;
                    }
                }
            }
        }
        return node;
    }

    /**
     * Resolve the string path and return the result
     *
     * @param path
     *
     * @return
     */
    private boolean resolvePath(String[] path) {
        PermissionNode node = getRootNode(path[0]);
        boolean hasAsterisk = false, asteriskValue = false;

        for (int current = 0; current < path.length; current++) {
            if (node == null) {
                return false;
            }
            if (node.isAsterisk()) {
                // File the value only and continue with resolving
                hasAsterisk = true;
                asteriskValue = node.getValue();
            }
            if (node.hasChildNode("*")) {
                // Register that we had an asterisk on the way, that's all we need to know!
                hasAsterisk = true;
                asteriskValue = node.getChildNode("*").getValue();
            }
            if (current + 1 < path.length) {
                if (node.hasChildNode(path[current + 1])) {
                    node = node.getChildNode(path[current + 1]);
                }
                else {
                    if (hasAsterisk) { // No subsequent nodes, the asterisk value wins
                        return asteriskValue;
                    }
                    // No asterisk was before this point, so it's false
                    return false;
                }
            }
        }
        // Path was fully resolved, check if there was an asterisk on the way
        if (hasAsterisk) {
            // Only use asterisk if there's no overriding value behind it on the path
            if (asteriskValue == node.getValue()) {
                return asteriskValue;
            }
        }
        // No asterisk or asterisk value is not the same.
        // The overriding node will be used
        return node.getValue();
    }

    /**
     * Checks if this permission provider actually has the given path loaded.
     *
     * @param path
     *
     * @return
     */
    private boolean hasPath(String[] path) {
        PermissionNode node = getRootNode(path[0]);

        for (int current = 0; current < path.length; current++) {
            if (current == 0) {
                node = getRootNode("*");
                if (node == null) {
                    node = getRootNode(path[0]);
                }
            }
            if (current + 1 < path.length) {
                if (node == null) {
                    return false;
                }
                if (node.hasChildNode(path[current + 1])) {
                    node = node.getChildNode(path[current + 1]);
                }
                else if (node.hasChildNode("*")) {
                    node = node.getChildNode("*");
                }
            }
        }
        return node != null && (node.getName().equals(path[path.length - 1]) || node.isAsterisk());
    }

    @Override
    public void addPermission(String path, boolean value, int id) {
        String[] paths = path.split("\\.");

        if (paths.length == 0) {
            paths = new String[]{ path }; // we have only one node (root)
        }
        PermissionNode node = addPath(paths, value);

        node.setId(id);
    }

    @Override
    public void addPermission(String path, boolean value) {
        addPermission(path, value, Canary.permissionManager().addPermission(path, value, owner, isPlayerProvider ? "player" : "group", this.world));
        // addPermission(path, value, permissions.size()); //Testing
        flushCache();
    }

    @Override
    public boolean queryPermission(String permission) {
        if (permission.isEmpty() || permission.equals(" ")) {
            return true;
        }
        Boolean b = checkCached(permission);
        if (b != null) {
            return b;
        }
        String[] path = permission.split("\\.");
        if (!this.hasPath(path)) {
            if (parent != null) {
                return parent.queryPermission(permission);
            }
        }
        boolean result = resolvePath(permission.split("\\."));
        addPermissionToCache(permission, result);

        return result;
    }

    @Override
    public boolean pathExists(String permission) {
        return permission.trim().isEmpty() || hasPath(permission.split("\\."));
    }

    @Override
    public void flushCache() {
        permissionCache.clear();
    }

    @Override
    public void reload() {
        permissions.clear();
        permissionCache.clear();
        if (isPlayerProvider) {
            PermissionProvider p = Canary.permissionManager().getPlayerProvider(owner, world);
            permissions = p.getPermissionMap();
        }
        else {
            PermissionProvider p = Canary.permissionManager().getGroupsProvider(owner, world);
            permissions = p.getPermissionMap();
        }
    }

    @Override
    public void setOwner(String owner) {
        this.owner = owner;
    }

    @Override
    public void setType(boolean isPlayerProvider) {
        this.isPlayerProvider = isPlayerProvider;
    }

    @Override
    public ArrayList<PermissionNode> getPermissionMap() {
        return permissions;
    }

    @Override
    public ArrayList<String> getPermissionsAsStringList() {
        ArrayList<String> list = new ArrayList<String>();

        for (PermissionNode node : permissions) {
            list.add(node.getFullPath());
        }
        return list;
    }

    @Override
    public void printPermissionsToCaller(MessageReceiver caller) {
        PermissionDataAccess data = new PermissionDataAccess(world);
        ArrayList<DataAccess> list = new ArrayList<DataAccess>();
        try {
            Database.get().loadAll(data, list, new String[]{ "owner", "type" }, new Object[]{ this.owner, isPlayerProvider ? "player" : "group" });
        }
        catch (DatabaseReadException e) {
            caller.notice(Translator.translate("no permissions"));
        }
        if (list.size() > 0) {
            for (DataAccess da : list) {
                PermissionDataAccess perm = (PermissionDataAccess) da;
                if (perm.value) {
                    caller.message(Colors.LIGHT_GREEN + perm.path + ": true");
                }
                else {
                    caller.message(Colors.LIGHT_RED + perm.path + ": false");
                }
            }
        }
        else {
            caller.notice(Translator.translate("no permissions"));
        }
    }

    @Override
    public String getWorld() {
        return world;
    }

    @Override
    public PermissionProvider getParent() {
        return parent;
    }
}
TOP

Related Classes of net.canarymod.permissionsystem.MultiworldPermissionProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.