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