/*
* PermissionsEx - Permissions plugin for Bukkit
* Copyright (C) 2011 t3hk0d3 http://www.tehkode.ru
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package pex.permissions;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
/**
*
* @author t3hk0d3
*/
public abstract class PermissionGroup extends PermissionEntity implements Comparable<PermissionGroup> {
protected final static String NON_INHERITABLE_PREFIX = "#";
protected int weight = 0;
protected boolean dirtyWeight = true;
public PermissionGroup(String groupName, PermissionManager manager) {
super(groupName, manager);
}
@Override
public void initialize() {
super.initialize();
if (isDebug()) {
Logger.getLogger("Minecraft").info("[PermissionsEx] Group " + getName() + " initialized");
}
}
/**
* Return non-inherited group prefix. This means if a group don't have has
* own prefix then empty string or null would be returned
*
* @return prefix as string
*/
public String getOwnPrefix() {
return this.getOwnPrefix(null);
}
public abstract String getOwnPrefix(String worldName);
/**
* Return non-inherited suffix prefix. This means if a group don't has own
* suffix then empty string or null would be returned
*
* @return suffix as string
*/
public final String getOwnSuffix() {
return this.getOwnSuffix(null);
}
public abstract String getOwnSuffix(String worldName);
/**
* Returns own (without inheritance) permissions of group for world
*
* @param world
* world's world name
* @return Array of permissions for world
*/
public abstract String[] getOwnPermissions(String world);
/**
* Returns option value in specified world without inheritance This mean
* option value wouldn't be inherited from parent groups
*
* @param option
* @param world
* @param defaultValue
* @return option value or defaultValue if option was not found in own
* options
*/
public abstract String getOwnOption(String option, String world, String defaultValue);
public String getOwnOption(String option) {
return this.getOwnOption(option, null, null);
}
public String getOwnOption(String option, String world) {
return this.getOwnOption(option, world, null);
}
public boolean getOwnOptionBoolean(String optionName, String world, boolean defaultValue) {
String option = this.getOwnOption(optionName, world, Boolean.toString(defaultValue));
if ("false".equalsIgnoreCase(option)) {
return false;
} else if ("true".equalsIgnoreCase(option)) {
return true;
}
return defaultValue;
}
public int getOwnOptionInteger(String optionName, String world, int defaultValue) {
String option = this.getOwnOption(optionName, world, Integer.toString(defaultValue));
try {
return Integer.parseInt(option);
} catch (NumberFormatException e) {
}
return defaultValue;
}
public double getOwnOptionDouble(String optionName, String world, double defaultValue) {
String option = this.getOwnOption(optionName, world, Double.toString(defaultValue));
try {
return Double.parseDouble(option);
} catch (NumberFormatException e) {
}
return defaultValue;
}
public int getWeight() {
if (dirtyWeight) {
weight = getOptionInteger("weight", null, 0);
dirtyWeight = false;
}
return weight;
}
public void setWeight(int weight) {
this.setOption("weight", Integer.toString(weight));
dirtyWeight = true;
clearMembersCache();
}
/**
* Checks if group is participating in ranking system
*
* @return
*/
public boolean isRanked() {
return getRank() > 0;
}
/**
* Returns rank in ranking system. 0 if group is not ranked
*
* @return
*/
public int getRank() {
return getOwnOptionInteger("rank", null, 0);
}
/**
* Set rank for this group
*
* @param rank
* Rank for group. Specify 0 to remove group from ranking
*/
public void setRank(int rank) {
if (rank > 0) {
this.setOption("rank", Integer.toString(rank));
} else {
this.setOption("rank", null);
}
}
/**
* Returns ranking ladder where this group is participating in
*
* @return Name of rank ladder as String
*/
public String getRankLadder() {
return this.getOption("rank-ladder", "", "default");
}
/**
* Set rank ladder for this group
*
* @param rankLadder
* Name of rank ladder
*/
public void setRankLadder(String rankLadder) {
if (rankLadder.isEmpty() || rankLadder.equals("default")) {
rankLadder = null;
}
this.setOption("rank-ladder", rankLadder);
}
protected abstract String[] getParentGroupsNamesImpl(String worldName);
/**
* Returns array of parent groups objects
*
* @return array of groups objects
*/
public PermissionGroup[] getParentGroups(String worldName) {
List<PermissionGroup> parentGroups = new LinkedList<PermissionGroup>();
for (String parentGroup : getParentGroupsNamesImpl(worldName)) {
// Yeah horrible thing, i know, that just safety from invoking empty
// named groups
parentGroup = parentGroup.trim();
if (parentGroup.isEmpty()) {
continue;
}
if (parentGroup.equals(getName())) {
continue;
}
PermissionGroup group = manager.getGroup(parentGroup);
if (!parentGroups.contains(group) && !group.isChildOf(this, worldName, true)) { // To
// prevent
// cyclic
// inheritance
parentGroups.add(group);
}
}
if (worldName != null) {
// World Inheritance
for (String parentWorld : manager.getWorldInheritance(worldName)) {
parentGroups.addAll(Arrays.asList(getParentGroups(parentWorld)));
}
parentGroups.addAll(Arrays.asList(getParentGroups(null)));
}
Collections.sort(parentGroups);
return parentGroups.toArray(new PermissionGroup[0]);
}
public PermissionGroup[] getParentGroups() {
return this.getParentGroups(null);
}
public Map<String, PermissionGroup[]> getAllParentGroups() {
Map<String, PermissionGroup[]> allGroups = new HashMap<String, PermissionGroup[]>();
for (String worldName : getWorlds()) {
allGroups.put(worldName, getWorldGroups(worldName));
}
allGroups.put(null, getWorldGroups(null));
return allGroups;
}
protected PermissionGroup[] getWorldGroups(String worldName) {
List<PermissionGroup> groups = new LinkedList<PermissionGroup>();
for (String groupName : getParentGroupsNamesImpl(worldName)) {
if (groupName == null || groupName.isEmpty() || groupName.equalsIgnoreCase(getName())) {
continue;
}
PermissionGroup group = manager.getGroup(groupName);
if (!groups.contains(group)) {
groups.add(group);
}
}
Collections.sort(groups);
return groups.toArray(new PermissionGroup[0]);
}
/**
* Returns direct parents names of this group
*
* @return array of parents group names
*/
public String[] getParentGroupsNames(String worldName) {
List<String> groups = new LinkedList<String>();
for (PermissionGroup group : this.getParentGroups(worldName)) {
groups.add(group.getName());
}
return groups.toArray(new String[0]);
}
public String[] getParentGroupsNames() {
return this.getParentGroupsNames(null);
}
/**
* Set parent groups
*
* @param parentGroups
* Array of parent groups names to set
*/
public abstract void setParentGroups(String[] parentGroups, String worldName);
public void setParentGroups(String[] parentGroups) {
this.setParentGroups(parentGroups, null);
}
/**
* Set parent groups
*
* @param parentGroups
* Array of parent groups objects to set
*/
public void setParentGroups(PermissionGroup[] parentGroups, String worldName) {
List<String> groups = new LinkedList<String>();
for (PermissionGroup group : parentGroups) {
groups.add(group.getName());
}
this.setParentGroups(groups.toArray(new String[0]), worldName);
}
public void setParentGroups(PermissionGroup[] parentGroups) {
this.setParentGroups(parentGroups, null);
}
protected abstract void removeGroup();
/**
* Check if this group is descendant of specified group
*
* @param group
* group object of parent
* @param checkInheritance
* set to false to check only the direct inheritance
* @return true if this group is descendant or direct parent of specified
* group
*/
public boolean isChildOf(PermissionGroup group, String worldName, boolean checkInheritance) {
if (group == null) {
return false;
}
for (PermissionGroup parentGroup : this.getParentGroups(worldName)) {
if (group.equals(parentGroup)) {
return true;
}
if (checkInheritance && parentGroup.isChildOf(group, worldName, checkInheritance)) {
return true;
}
}
return false;
}
public boolean isChildOf(PermissionGroup group, boolean checkInheritance) {
for (String worldName : getWorlds()) {
if (this.isChildOf(group, worldName, checkInheritance)) {
return true;
}
}
return this.isChildOf(group, null, checkInheritance);
}
public boolean isChildOf(PermissionGroup group, String worldName) {
return isChildOf(group, worldName, false);
}
public boolean isChildOf(PermissionGroup group) {
return isChildOf(group, false);
}
/**
* Check if this group is descendant of specified group
*
* @param groupName
* name of group to check against
* @param checkInheritance
* set to false to check only the direct inheritance
* @return
*/
public boolean isChildOf(String groupName, String worldName, boolean checkInheritance) {
return isChildOf(manager.getGroup(groupName), worldName, checkInheritance);
}
public boolean isChildOf(String groupName, boolean checkInheritance) {
return isChildOf(manager.getGroup(groupName), checkInheritance);
}
/**
* Check if specified group is direct parent of this group
*
* @param groupName
* to check against
* @return
*/
public boolean isChildOf(String groupName, String worldName) {
return this.isChildOf(groupName, worldName, false);
}
public boolean isChildOf(String groupName) {
return this.isChildOf(groupName, false);
}
/**
* Return array of direct child group objects
*
* @return
*/
public PermissionGroup[] getChildGroups(String worldName) {
return manager.getGroups(getName(), worldName, false);
}
public PermissionGroup[] getChildGroups() {
return manager.getGroups(getName(), false);
}
/**
* Return array of descendant group objects
*
* @return
*/
public PermissionGroup[] getDescendantGroups(String worldName) {
return manager.getGroups(getName(), worldName, true);
}
public PermissionGroup[] getDescendantGroups() {
return manager.getGroups(getName(), true);
}
/**
* Return array of direct members (users) of this group
*
* @return
*/
public PermissionUser[] getUsers(String worldName) {
return manager.getUsers(getName(), worldName, false);
}
public PermissionUser[] getUsers() {
return manager.getUsers(getName());
}
public boolean isDefault(String worldName) {
return equals(manager.getDefaultGroup(worldName));
}
/**
* Overriden methods
*/
@Override
public String getPrefix(String worldName) {
// @TODO This method should be refactored
String localPrefix = this.getOwnPrefix(worldName);
if (worldName != null && (localPrefix == null || localPrefix.isEmpty())) {
// World-inheritance
for (String parentWorld : manager.getWorldInheritance(worldName)) {
String prefix = this.getOwnPrefix(parentWorld);
if (prefix != null && !prefix.isEmpty()) {
localPrefix = prefix;
break;
}
}
// Common space
if (localPrefix == null || localPrefix.isEmpty()) {
localPrefix = this.getOwnPrefix(null);
}
}
if (localPrefix == null || localPrefix.isEmpty()) {
for (PermissionGroup group : this.getParentGroups(worldName)) {
localPrefix = group.getPrefix(worldName);
if (localPrefix != null && !localPrefix.isEmpty()) {
break;
}
}
}
if (localPrefix == null) { // NPE safety
localPrefix = "";
}
return localPrefix;
}
@Override
public String getSuffix(String worldName) {
// @TODO This method should be refactored
String localSuffix = this.getOwnSuffix(worldName);
if (worldName != null && (localSuffix == null || localSuffix.isEmpty())) {
// World-inheritance
for (String parentWorld : manager.getWorldInheritance(worldName)) {
String suffix = this.getOwnSuffix(parentWorld);
if (suffix != null && !suffix.isEmpty()) {
localSuffix = suffix;
break;
}
}
// Common space
if (localSuffix == null || localSuffix.isEmpty()) {
localSuffix = this.getOwnSuffix(null);
}
}
if (localSuffix == null || localSuffix.isEmpty()) {
for (PermissionGroup group : this.getParentGroups(worldName)) {
localSuffix = group.getSuffix(worldName);
if (localSuffix != null && !localSuffix.isEmpty()) {
break;
}
}
}
if (localSuffix == null) { // NPE safety
localSuffix = "";
}
return localSuffix;
}
@Override
public String[] getPermissions(String world) {
List<String> permissions = new LinkedList<String>();
getInheritedPermissions(world, permissions, true, false, true);
return permissions.toArray(new String[0]);
}
@Override
public void addPermission(String permission, String worldName) {
List<String> permissions = new LinkedList<String>(Arrays.asList(getOwnPermissions(worldName)));
if (permissions.contains(permission)) {
permissions.remove(permission);
}
permissions.add(0, permission);
this.setPermissions(permissions.toArray(new String[0]), worldName);
}
@Override
public void removePermission(String permission, String worldName) {
List<String> permissions = new LinkedList<String>(Arrays.asList(getOwnPermissions(worldName)));
permissions.remove(permission);
this.setPermissions(permissions.toArray(new String[0]), worldName);
}
protected void getInheritedPermissions(String worldName, List<String> permissions, boolean groupInheritance, boolean worldInheritance, boolean firstStep) {
if (firstStep) {
permissions.addAll(Arrays.asList(getTimedPermissions(worldName)));
permissions.addAll(Arrays.asList(getOwnPermissions(worldName)));
} else { // filter permissions for ancestors groups
copyFilterPermissions(NON_INHERITABLE_PREFIX, permissions, getTimedPermissions(worldName));
copyFilterPermissions(NON_INHERITABLE_PREFIX, permissions, getOwnPermissions(worldName));
}
if (worldName != null) {
// World inheritance
for (String parentWorld : manager.getWorldInheritance(worldName)) {
getInheritedPermissions(parentWorld, permissions, false, true, firstStep);
}
// Common permission
if (!worldInheritance) {
getInheritedPermissions(null, permissions, false, true, firstStep);
}
}
// Group inhertance
if (groupInheritance) {
for (PermissionGroup group : this.getParentGroups(worldName)) {
group.getInheritedPermissions(worldName, permissions, true, false, false);
}
}
}
protected void copyFilterPermissions(String filterPrefix, List<String> to, String[] from) {
for (String permission : from) {
if (permission.startsWith(filterPrefix)) {
continue;
}
to.add(permission);
}
}
@Override
public void addTimedPermission(String permission, String world, int lifeTime) {
super.addTimedPermission(permission, world, lifeTime);
clearMembersCache();
}
@Override
public void removeTimedPermission(String permission, String world) {
super.removeTimedPermission(permission, world);
clearMembersCache();
}
protected void clearMembersCache() {
for (PermissionUser user : this.getUsers()) {
user.clearCache();
}
}
@Override
public final void remove() {
for (String world : getWorlds()) {
clearChildren(world);
}
clearChildren(null);
removeGroup();
}
private void clearChildren(String worldName) {
for (PermissionGroup group : this.getChildGroups(worldName)) {
List<PermissionGroup> parentGroups = new LinkedList<PermissionGroup>(Arrays.asList(group.getParentGroups(worldName)));
parentGroups.remove(this);
group.setParentGroups(parentGroups.toArray(new PermissionGroup[0]), worldName);
}
for (PermissionUser user : this.getUsers(worldName)) {
user.removeGroup(this, worldName);
}
}
@Override
public String getOption(String optionName, String worldName, String defaultValue) {
String value = this.getOwnOption(optionName, worldName, null);
if (value != null) {
return value;
}
if (worldName != null) { // world inheritance
for (String world : manager.getWorldInheritance(worldName)) {
value = this.getOption(optionName, world, null);
if (value != null) {
return value;
}
}
// Check common space
value = this.getOption(optionName, null, null);
if (value != null) {
return value;
}
}
// Inheritance
for (PermissionGroup group : this.getParentGroups(worldName)) {
value = group.getOption(optionName, worldName, null);
if (value != null) {
return value;
}
}
// Nothing found
return defaultValue;
}
@Override
public int compareTo(PermissionGroup o) {
return getWeight() - o.getWeight();
}
}