001/* This file is part of Vault.
002
003    Vault is free software: you can redistribute it and/or modify
004    it under the terms of the GNU Lesser General Public License as published by
005    the Free Software Foundation, either version 3 of the License, or
006    (at your option) any later version.
007
008    Vault is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU Lesser General Public License for more details.
012
013    You should have received a copy of the GNU Lesser General Public License
014    along with Vault.  If not, see <http://www.gnu.org/licenses/>.
015 */
016package net.milkbowl.vault.permission;
017
018import java.util.UUID;
019import java.util.logging.Logger;
020
021import org.bukkit.Bukkit;
022import org.bukkit.World;
023import org.bukkit.command.CommandSender;
024import org.bukkit.entity.Player;
025import org.bukkit.permissions.PermissionAttachment;
026import org.bukkit.permissions.PermissionAttachmentInfo;
027import org.bukkit.plugin.Plugin;
028
029/**
030 * The main Permission API - allows for group and player based permission tests
031 *
032 */
033public abstract class Permission {
034
035        protected static final Logger log = Logger.getLogger("Minecraft");
036    protected Plugin plugin = null;
037
038    /**
039     * Gets name of permission method
040     * @return Name of Permission Method
041     */
042    abstract public String getName();
043
044    /**
045     * Checks if permission method is enabled.
046     * @return Success or Failure
047     */
048    abstract public boolean isEnabled();
049    
050    /**
051     * Returns if the permission system is or attempts to be compatible with super-perms.
052     * @return True if this permission implementation works with super-perms
053     */
054    abstract public boolean hasSuperPermsCompat();
055    
056    /**
057     * Checks if player has a permission node. (Short for playerHas(...)
058     * Supports NULL value for World if the permission system registered supports global permissions.
059     * But May return odd values if the servers registered permission system does not have a global permission store.
060     * 
061     * @param world World name
062     * @param player Player name
063     * @param permission Permission node
064     * @return Success or Failure
065     */
066    public boolean has(String world, String player, String permission) {
067        if (world == null) {
068            return playerHas((String) null, player, permission);
069        }
070        return playerHas(world, player, permission);
071    }
072
073    /**
074     * Checks if player has a permission node. (Short for playerHas(...)
075     * Supports NULL value for World if the permission system registered supports global permissions.
076     * But May return odd values if the servers registered permission system does not have a global permission store.
077     * 
078     * @param world World Object
079     * @param player Player name
080     * @param permission Permission node
081     * @return Success or Failure
082     */
083    public boolean has(World world, String player, String permission) {
084        if (world == null) {
085            return playerHas((String) null, player, permission);
086        }
087        return playerHas(world.getName(), player, permission);
088    }
089
090    /**
091     * Checks if a CommandSender has a permission node.
092     * This will return the result of bukkits, generic .hasPermission() method and is identical in all cases.
093     * This method will explicitly fail if the registered permission system does not register permissions in bukkit.
094     * 
095     * For easy checking of a commandsender
096     * @param sender to check permissions on
097     * @param permission to check for
098     * @return true if the sender has the permission
099     */
100    public boolean has(CommandSender sender, String permission) {
101        return sender.hasPermission(permission);
102    }
103
104    /**
105     * Checks if player has a permission node. (Short for playerHas(...)
106     * @param player Player Object
107     * @param permission Permission node
108     * @return Success or Failure
109     */
110    public boolean has(Player player, String permission) {
111        return player.hasPermission(permission);
112    }
113
114    /**
115     * Checks if player has a permission node.
116     * Supports NULL value for World if the permission system registered supports global permissions.
117     * But May return odd values if the servers registered permission system does not have a global permission store.
118     * 
119     * @param world World name
120     * @param player Player name
121     * @param permission Permission node
122     * @return Success or Failure
123     */
124    abstract public boolean playerHas(String world, String player, String permission);
125
126    /**
127     * Checks if player has a permission node.
128     * Supports NULL value for World if the permission system registered supports global permissions.
129     * But May return odd values if the servers registered permission system does not have a global permission store.
130     * 
131     * @param world World Object
132     * @param player Player name
133     * @param permission Permission node
134     * @return Success or Failure
135     */
136    public boolean playerHas(World world, String player, String permission) {
137        if (world == null) {
138            return playerHas((String) null, player, permission);
139        }
140        return playerHas(world.getName(), player, permission);
141    }
142    
143    /**
144     * Checks if player has a permission node.
145     * 
146     * @param world World Object
147     * @param playerId UUID of the player
148     * @param permission Permission node
149     * @return Success or Failure
150     */
151    public boolean playerHas(World world, UUID playerId, String permission) {
152        if (world == null) {
153                return has((String) null, Bukkit.getOfflinePlayer(playerId).getName(), permission);
154        }
155        return has(world.getName(), Bukkit.getOfflinePlayer(playerId).getName(), permission);
156    }
157
158    /**
159     * Checks if player has a permission node.
160     * @param player Player Object
161     * @param permission Permission node
162     * @return Success or Failure
163     */
164    public boolean playerHas(Player player, String permission) {
165        return has(player, permission);
166    }
167
168    /**
169     * Add permission to a player.
170     * Supports NULL value for World if the permission system registered supports global permissions.
171     * But May return odd values if the servers registered permission system does not have a global permission store.
172     * 
173     * @param world World name
174     * @param player Player name
175     * @param permission Permission node
176     * @return Success or Failure
177     */
178    abstract public boolean playerAdd(String world, String player, String permission);
179
180    /**
181     * Add permission to a player.
182     * Supports NULL value for World if the permission system registered supports global permissions.
183     * But May return odd values if the servers registered permission system does not have a global permission store.
184     * 
185     * @param world World Object
186     * @param player Player name
187     * @param permission Permission node
188     * @return Success or Failure
189     */
190    public boolean playerAdd(World world, String player, String permission) {
191        if (world == null) {
192            return playerAdd((String) null, player, permission);
193        }
194        return playerAdd(world.getName(), player, permission);
195    }
196
197    /**
198     * Add permission to a player.
199     * Supports NULL value for World if the permission system registered supports global permissions.
200     * But May return odd values if the servers registered permission system does not have a global permission store.
201     * 
202     * @param world World Object
203     * @param playerId UUId of the player
204     * @param permission Permission node
205     * @return Success or Failure
206     */
207    public boolean playerAdd(World world, UUID playerId, String permission) {
208        if (world == null) {
209            return playerAdd((String) null, Bukkit.getOfflinePlayer(playerId).getName(), permission);
210        }
211        return playerAdd(world.getName(), Bukkit.getOfflinePlayer(playerId).getName(), permission);
212    }
213
214    /**
215     * Add permission to a player ONLY for the world the player is currently on.
216     * This is a world-specific operation, if you want to add global permission you must explicitly use NULL for the world.
217     * 
218     * @param player Player Object
219     * @param permission Permission node
220     * @return Success or Failure
221     */
222    public boolean playerAdd(Player player, String permission) {
223        return playerAdd(player.getWorld().getName(), player.getName(), permission);
224    }
225    
226    /**
227     * Add transient permission to a player.
228     * This implementation can be used by any subclass which implements a "pure" superperms plugin, i.e. 
229     * one that only needs the built-in Bukkit API to add transient permissions to a player.  Any subclass
230     * implementing a plugin which provides its own API for this needs to override this method. 
231     * 
232     * @param player Player name
233     * @param permission Permission node
234     * @return Success or Failure
235     */
236    public boolean playerAddTransient(String player, String permission) throws UnsupportedOperationException {
237                Player p = plugin.getServer().getPlayer(player);
238                if (p == null) {
239                        throw new UnsupportedOperationException(getName() + " does not support offline player transient permissions!");
240                }
241                return playerAddTransient(p, permission);
242        }
243    
244    /**
245     * Add transient permission to a player.
246     * This implementation can be used by any subclass which implements a "pure" superperms plugin, i.e. 
247     * one that only needs the built-in Bukkit API to add transient permissions to a player.
248     * 
249     * @param playerId UUID
250     * @param permission Permission node
251     * @return Success or Failure
252     */
253    public boolean playerAddTransient(UUID playerId, String permission) throws UnsupportedOperationException {
254                Player p = plugin.getServer().getPlayer(playerId);
255                if (p == null) {
256                        throw new UnsupportedOperationException(getName() + " does not support offline player transient permissions!");
257                }
258                return playerAddTransient(p, permission);
259        }
260
261    /**
262     * Add transient permission to a player.
263     * This operation adds a world-unspecific permission onto the player object in bukkit via Bukkit's permission interface.
264     * 
265     * @param player Player Object
266     * @param permission Permission node
267     * @return Success or Failure
268     */
269    public boolean playerAddTransient(Player player, String permission) {
270                for (PermissionAttachmentInfo paInfo : player.getEffectivePermissions()) {
271                        if (paInfo.getAttachment() != null && paInfo.getAttachment().getPlugin().equals(plugin)) {
272                                paInfo.getAttachment().setPermission(permission, true);
273                                return true;
274                        }
275                }
276
277                PermissionAttachment attach = player.addAttachment(plugin);
278                attach.setPermission(permission, true);
279
280                return true;
281    }
282
283    /**
284     * Adds a world specific transient permission to the player - ONLY WORKS IN PEX/P3 - otherwise it defaults to GLOBAL!
285     * 
286     * @param worldName to check on
287     * @param playerId UUID
288     * @param permission to test
289     * @return Success or Failure
290     */
291    public boolean playerAddTransient(String worldName, UUID playerId, String permission) {
292        return playerAddTransient(playerId, permission);
293    }
294    
295    /**
296     * Adds a world specific transient permission to the player - ONLY WORKS IN PEX/P3 - otherwise it defaults to GLOBAL!
297     * @param worldName to check on
298     * @param player to check
299     * @param permission to check for
300     * @return Success or Failure
301     */
302    public boolean playerAddTransient(String worldName, Player player, String permission) {
303        return playerAddTransient(player, permission);
304    }
305    
306    /**
307     * Adds a world specific transient permission to the player - ONLY WORKS IN PEX/P3 - otherwise it defaults to GLOBAL!
308     * @param worldName to check on
309     * @param player to check
310     * @param permission to check
311     * @return Success or Failure
312     */
313    public boolean playerAddTransient(String worldName, String player, String permission) {
314                Player p = plugin.getServer().getPlayer(player);
315                if (p == null) {
316                        throw new UnsupportedOperationException(getName() + " does not support offline player transient permissions!");
317                }
318                return playerAddTransient(p, permission);
319    }
320    
321    /**
322     * Removes a world specific transient permission from the player - Only works in PEX/P3 - otherwise it defaults to Global!
323     * @param worldName to check on
324     * @param player to check
325     * @param permission to check for
326     * @return Success or Failure
327     */
328        public boolean playerRemoveTransient(String worldName, String player, String permission) {
329                Player p = plugin.getServer().getPlayer(player);
330                if (p == null)
331                        return false;
332                
333                return playerRemoveTransient(p, permission);
334        }
335        
336    /**
337     * Removes a world specific transient permission from the player - Only works in PEX/P3 - otherwise it defaults to Global!
338     * @param worldName to check on
339     * @param playerId UUID to check
340     * @param permission to check for
341     * @return Success or Failure
342     */
343    public boolean playerRemoveTransient(String worldName, UUID playerId, String permission) {
344        return playerRemoveTransient(playerId, permission);
345    }
346        
347    /**
348     * Removes a world specific transient permission from the player - Only works in PEX/P3 - otherwise it defaults to Global!
349     * @param worldName to check on
350     * @param player to check
351     * @param permission to check for
352     * @return Success or Failure
353     */
354    public boolean playerRemoveTransient(String worldName, Player player, String permission) {
355        return playerRemoveTransient(player, permission);
356    }
357    
358    /**
359     * Remove permission from a player.
360     * @param world World name
361     * @param player Name of Player
362     * @param permission Permission node
363     * @return Success or Failure
364     */
365    abstract public boolean playerRemove(String world, String player, String permission);
366
367    /**
368     * Remove permission from a player.
369     * Supports NULL value for World if the permission system registered supports global permissions.
370     * But May return odd values if the servers registered permission system does not have a global permission store.
371     * 
372     * @param world World name
373     * @param player Player name
374     * @param permission Permission node
375     * @return Success or Failure
376     */
377    public boolean playerRemove(World world, String player, String permission) {
378        if (world == null) {
379            return playerRemove((String) null, player, permission);
380        }
381        return playerRemove(world.getName(), player, permission);
382    }
383
384    /**
385     * Remove permission from a player.
386     * Will attempt to remove permission from the player on the player's current world.  This is NOT a global operation.
387     * 
388     * @param player Player Object
389     * @param permission Permission node
390     * @return Success or Failure
391     */
392    public boolean playerRemove(Player player, String permission) {
393        return playerRemove(player.getWorld().getName(), player.getName(), permission);
394    }
395    
396    /**
397     * Remove transient permission from a player.
398     * This implementation can be used by any subclass which implements a "pure" superperms plugin, i.e. 
399     * one that only needs the built-in Bukkit API to remove transient permissions from a player.  Any subclass
400     * implementing a plugin which provides its own API for this needs to override this method.
401     * 
402     * @param player Player name
403     * @param permission Permission node
404     * @return Success or Failure
405     */
406        public boolean playerRemoveTransient(String player, String permission) {
407                Player p = plugin.getServer().getPlayer(player);
408                if (p == null)
409                        return false;
410                
411                return playerRemoveTransient(p, permission);
412        }
413        
414
415    /**
416     * Remove transient permission from a player.
417     * 
418     * @param playerId UUID
419     * @param permission Permission node
420     * @return Success or Failure
421     */
422    public boolean playerRemoveTransient(UUID playerId, String permission) {
423                return playerRemoveTransient(Bukkit.getPlayer(playerId), permission);
424    }
425
426    /**
427     * Remove transient permission from a player.
428     * 
429     * @param player Player Object
430     * @param permission Permission node
431     * @return Success or Failure
432     */
433    public boolean playerRemoveTransient(Player player, String permission) {
434                for (PermissionAttachmentInfo paInfo : player.getEffectivePermissions()) {
435                        if (paInfo.getAttachment() != null && paInfo.getAttachment().getPlugin().equals(plugin)) {
436                                paInfo.getAttachment().unsetPermission(permission);
437                                return true;
438                        }
439                }
440                return false;
441    }
442    
443    /**
444     * Checks if group has a permission node.
445     * Supports NULL value for World if the permission system registered supports global permissions.
446     * But May return odd values if the servers registered permission system does not have a global permission store.
447     * 
448     * @param world World name
449     * @param group Group name
450     * @param permission Permission node
451     * @return Success or Failure
452     */
453    abstract public boolean groupHas(String world, String group, String permission);
454
455    /**
456     * Checks if group has a permission node.
457     * Supports NULL value for World if the permission system registered supports global permissions.
458     * But May return odd values if the servers registered permission system does not have a global permission store.
459     * 
460     * @param world World Object
461     * @param group Group name
462     * @param permission Permission node
463     * @return Success or Failure
464     */
465    public boolean groupHas(World world, String group, String permission) {
466        if (world == null) {
467            return groupHas((String) null, group, permission);
468        }
469        return groupHas(world.getName(), group, permission);
470    }
471
472    /**
473     * Add permission to a group.
474     * Supports NULL value for World if the permission system registered supports global permissions.
475     * But May return odd values if the servers registered permission system does not have a global permission store.
476     * 
477     * @param world World name
478     * @param group Group name
479     * @param permission Permission node
480     * @return Success or Failure
481     */
482    abstract public boolean groupAdd(String world, String group, String permission);
483
484    /**
485     * Add permission to a group.
486     * Supports NULL value for World if the permission system registered supports global permissions.
487     * But May return odd values if the servers registered permission system does not have a global permission store.
488     * 
489     * @param world World Object
490     * @param group Group name
491     * @param permission Permission node
492     * @return Success or Failure
493     */
494    public boolean groupAdd(World world, String group, String permission) {
495        if (world == null) {
496            return groupAdd((String) null, group, permission);
497        }
498        return groupAdd(world.getName(), group, permission);
499    }
500
501    /**
502     * Remove permission from a group.
503     * Supports NULL value for World if the permission system registered supports global permissions.
504     * But May return odd values if the servers registered permission system does not have a global permission store.
505     * 
506     * @param world World name
507     * @param group Group name
508     * @param permission Permission node
509     * @return Success or Failure
510     */
511    abstract public boolean groupRemove(String world, String group, String permission);
512
513    /**
514     * Remove permission from a group.
515     * Supports NULL value for World if the permission system registered supports global permissions.
516     * But May return odd values if the servers registered permission system does not have a global permission store.
517     * 
518     * @param world World Object
519     * @param group Group name
520     * @param permission Permission node
521     * @return Success or Failure
522     */
523    public boolean groupRemove(World world, String group, String permission) {
524        if (world == null) {
525            return groupRemove((String) null, group, permission);
526        }
527        return groupRemove(world.getName(), group, permission);
528    }
529
530    /**
531     * Check if player is member of a group.
532     * Supports NULL value for World if the permission system registered supports global permissions.
533     * But May return odd values if the servers registered permission system does not have a global permission store.
534     * 
535     * This method is known to return unexpected results depending on what permission system is being used. Different permission systems
536     * will store the player groups differently, It is HIGHLY suggested you test your code out first.
537     * 
538     * @param world World name
539     * @param player Player name
540     * @param group Group name
541     * @return Success or Failure
542     */
543    abstract public boolean playerInGroup(String world, String player, String group);
544
545    /**
546     * Check if player is member of a group.
547     * Supports NULL value for World if the permission system registered supports global permissions.
548     * But May return odd values if the servers registered permission system does not have a global permission store.
549     * 
550     * @param world World Object
551     * @param player Player name
552     * @param group Group name
553     * @return Success or Failure
554     */
555    public boolean playerInGroup(World world, String player, String group) {
556        if (world == null) {
557            return playerInGroup((String) null, player, group);
558        }
559        return playerInGroup(world.getName(), player, group);
560    }
561    
562    /**
563     * Check if player is member of a group.
564     * Supports NULL value for World if the permission system registered supports global permissions.
565     * But May return odd values if the servers registered permission system does not have a global permission store.
566     * 
567     * @param world World Object
568     * @param playerId UUID
569     * @param group Group name
570     * @return Success or Failure
571     */
572    public boolean playerInGroup(World world, UUID playerId, String group) {
573        if (world == null) {
574            return playerInGroup((String) null, Bukkit.getOfflinePlayer(playerId).getName(), group);
575        }
576        return playerInGroup(world.getName(), Bukkit.getOfflinePlayer(playerId).getName(), group);
577    }
578
579    /**
580     * Check if player is member of a group.
581     * This method will ONLY check groups for which the player is in that are defined for the current world.
582     * This may result in odd return behaviour depending on what permission system has been registered.
583     * 
584     * @param player Player Object
585     * @param group Group name
586     * @return Success or Failure
587     */
588    public boolean playerInGroup(Player player, String group) {
589        return playerInGroup(player.getWorld().getName(), player.getName(), group);
590    }
591
592    /**
593     * Add player to a group.
594     * Supports NULL value for World if the permission system registered supports global permissions.
595     * But May return odd values if the servers registered permission system does not have a global permission store.
596     * 
597     * @param world World name
598     * @param player Player name
599     * @param group Group name
600     * @return Success or Failure
601     */
602    abstract public boolean playerAddGroup(String world, String player, String group);
603
604    /**
605     * Add player to a group.
606     * Supports NULL value for World if the permission system registered supports global permissions.
607     * But May return odd values if the servers registered permission system does not have a global permission store.
608     * 
609     * @param world World Object
610     * @param player Player name
611     * @param group Group name
612     * @return Success or Failure
613     */
614    public boolean playerAddGroup(World world, String player, String group) {
615        if (world == null) {
616            return playerAddGroup((String) null, player, group);
617        }
618        return playerAddGroup(world.getName(), player, group);
619    }
620
621    /**
622     * Add player to a group.
623     * Supports NULL value for World if the permission system registered supports global permissions.
624     * But May return odd values if the servers registered permission system does not have a global permission store.
625     * 
626     * @param world World Object
627     * @param playerId UUID
628     * @param group Group name
629     * @return Success or Failure
630     */
631    public boolean playerAddGroup(World world, UUID playerId, String group) {
632        if (world == null) {
633            return playerAddGroup((String) null, Bukkit.getOfflinePlayer(playerId).getName(), group);
634        }
635        return playerAddGroup(world.getName(), Bukkit.getOfflinePlayer(playerId).getName(), group);
636    }
637    
638    /**
639     * Add player to a group.
640     * This will add a player to the group on the current World.  This may return odd results if the permission system
641     * being used on the server does not support world-specific groups, or if the group being added to is a global group.
642     * 
643     * @param player Player Object
644     * @param group Group name
645     * @return Success or Failure
646     */
647    public boolean playerAddGroup(Player player, String group) {
648        return playerAddGroup(player.getWorld().getName(), player.getName(), group);
649    }
650
651    /**
652     * Remove player from a group.
653     * Supports NULL value for World if the permission system registered supports global permissions.
654     * But May return odd values if the servers registered permission system does not have a global permission store.
655     * 
656     * @param world World name
657     * @param player Player name
658     * @param group Group name
659     * @return Success or Failure
660     */
661    abstract public boolean playerRemoveGroup(String world, String player, String group);
662
663    /**
664     * Remove player from a group.
665     * Supports NULL value for World if the permission system registered supports global permissions.
666     * But May return odd values if the servers registered permission system does not have a global permission store.
667     * 
668     * @param world World Object
669     * @param player Player name
670     * @param group Group name
671     * @return Success or Failure
672     */
673    public boolean playerRemoveGroup(World world, String player, String group) {
674        if (world == null) {
675            return playerRemoveGroup((String) null, player, group);
676        }
677        return playerRemoveGroup(world.getName(), player, group);
678    }
679    
680    /**
681     * Remove player from a group.
682     * Supports NULL value for World if the permission system registered supports global permissions.
683     * But May return odd values if the servers registered permission system does not have a global permission store.
684     * 
685     * @param world World Object
686     * @param playerId UUID
687     * @param group Group name
688     * @return Success or Failure
689     */
690    public boolean playerRemoveGroup(World world, UUID playerId, String group) {
691        if (world == null) {
692            return playerRemoveGroup((String) null, Bukkit.getOfflinePlayer(playerId).getName(), group);
693        }
694        return playerRemoveGroup(world.getName(), Bukkit.getOfflinePlayer(playerId).getName(), group);
695    }
696
697    /**
698     * Remove player from a group.
699     * This will add a player to the group on the current World.  This may return odd results if the permission system
700     * being used on the server does not support world-specific groups, or if the group being added to is a global group.
701     * 
702     * @param player Player Object
703     * @param group Group name
704     * @return Success or Failure
705     */
706    public boolean playerRemoveGroup(Player player, String group) {
707        return playerRemoveGroup(player.getWorld().getName(), player.getName(), group);
708    }
709
710    /**
711     * Gets the list of groups that this player has.
712     * Supports NULL value for World if the permission system registered supports global permissions.
713     * But May return odd values if the servers registered permission system does not have a global permission store.
714     * 
715     * @param world World name
716     * @param player Player name
717     * @return Array of groups
718     */
719    abstract public String[] getPlayerGroups(String world, String player);
720
721    /**
722     * Gets the list of groups that this player has
723     * Supports NULL value for World if the permission system registered supports global permissions.
724     * But May return odd values if the servers registered permission system does not have a global permission store.
725     * 
726     * @param world World Object
727     * @param player Player name
728     * @return Array of groups
729     */
730    public String[] getPlayerGroups(World world, String player) {
731        if (world == null) {
732            return getPlayerGroups((String) null, player);
733        }
734        return getPlayerGroups(world.getName(), player);
735    }
736    
737    /**
738     * Gets the list of groups that this player has
739     * Supports NULL value for World if the permission system registered supports global permissions.
740     * But May return odd values if the servers registered permission system does not have a global permission store.
741     * 
742     * @param world World Object
743     * @param playerId UUID
744     * @return Array of groups
745     */
746    public String[] getPlayerGroups(World world, UUID playerId) {
747        return getPlayerGroups(world, Bukkit.getOfflinePlayer(playerId).getName());
748    }
749
750    /**
751     * Returns a list of world-specific groups that this player is currently in. May return unexpected results if
752     * you are looking for global groups, or if the registered permission system does not support world-specific groups.
753     * 
754     * @param player Player Object
755     * @return Array of groups
756     */
757    public String[] getPlayerGroups(Player player) {
758        return getPlayerGroups(player.getWorld().getName(), player.getName());
759    }
760
761    /**
762     * Gets players primary group
763     * Supports NULL value for World if the permission system registered supports global permissions.
764     * But May return odd values if the servers registered permission system does not have a global permission store.
765     * 
766     * @param world World name
767     * @param player Player name
768     * @return Players primary group
769     */
770    abstract public String getPrimaryGroup(String world, String player);
771
772    /**
773     * Gets players primary group
774     * Supports NULL value for World if the permission system registered supports global permissions.
775     * But May return odd values if the servers registered permission system does not have a global permission store.
776     * 
777     * @param world World Object
778     * @param player Player name
779     * @return Players primary group
780     */
781    public String getPrimaryGroup(World world, String player) {
782        if (world == null) {
783            return getPrimaryGroup((String) null, player);
784        }
785        return getPrimaryGroup(world.getName(), player);
786    }
787    
788    /**
789     * Gets players primary group
790     * Supports NULL value for World if the permission system registered supports global permissions.
791     * But May return odd values if the servers registered permission system does not have a global permission store.
792     * 
793     * @param world World Object
794     * @param playerId UUID of the player
795     * @return Players primary group
796     */
797    public String getPrimaryGroup(World world, UUID playerId) {
798        return getPrimaryGroup(world, Bukkit.getOfflinePlayer(playerId).getName());
799    }
800
801    /**
802     * Get players primary group
803     * @param player Player Object
804     * @return Players primary group
805     */
806    public String getPrimaryGroup(Player player) {
807        return getPrimaryGroup(player.getWorld().getName(), player.getName());
808    }
809    
810    /**
811     * Returns a list of all known groups
812     * @return an Array of String of all groups
813     */
814    abstract public String[] getGroups();
815    
816    /**
817     * Returns true if the given implementation supports groups.
818     * @return true if the implementation supports groups
819     */
820    abstract public boolean hasGroupSupport();
821}