001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027package org.opends.server.api; 028 029import org.forgerock.i18n.LocalizableMessage; 030 031import java.util.HashSet; 032import java.util.List; 033import java.util.Set; 034 035import org.opends.server.admin.std.server.GroupImplementationCfg; 036import org.opends.server.core.ServerContext; 037import org.forgerock.opendj.config.server.ConfigException; 038import org.opends.server.types.DirectoryException; 039import org.opends.server.types.DN; 040import org.opends.server.types.Entry; 041import org.opends.server.types.InitializationException; 042import org.opends.server.types.MemberList; 043import org.opends.server.types.SearchFilter; 044import org.forgerock.opendj.ldap.SearchScope; 045 046/** 047 * This class defines the set of methods that must be implemented by a 048 * Directory Server group. It is expected that there will be a number 049 * of different types of groups (e.g., legacy static and dynamic 050 * groups, as well as enhanced groups and virtual static groups). The 051 * following operations may be performed on an OpenDS group: 052 * <UL> 053 * <LI>Determining whether a given user is a member of this 054 * group</LI> 055 * <LI>Determining the set of members for this group, optionally 056 * filtered based on some set of criteria.</LI> 057 * <LI>Retrieving or updating the set of nested groups for this 058 * group, if the underlying group type supports nesting).</LI> 059 * <LI>Updating the set of members for this group, if the underlying 060 * group type provides the ability to explicitly add or remove 061 * members.</LI> 062 * </UL> 063 * 064 * @param <T> The type of configuration handled by this group 065 * implementation. 066 */ 067@org.opends.server.types.PublicAPI( 068 stability=org.opends.server.types.StabilityLevel.VOLATILE, 069 mayInstantiate=false, 070 mayExtend=true, 071 mayInvoke=true) 072public abstract class Group<T extends GroupImplementationCfg> 073{ 074 /** 075 * Initializes a "shell" instance of this group implementation that 076 * may be used to identify and instantiate instances of this type of 077 * group in the directory data. 078 * 079 * @param configuration The configuration for this group 080 * implementation. 081 * 082 * @throws ConfigException If there is a problem with the provided 083 * configuration entry. 084 * 085 * @throws InitializationException If a problem occurs while 086 * attempting to initialize this 087 * group implementation that is 088 * not related to the server 089 * configuration. 090 */ 091 public abstract void initializeGroupImplementation(T configuration) 092 throws ConfigException, InitializationException; 093 094 095 096 /** 097 * Indicates whether the provided configuration is acceptable for 098 * this group implementation. It should be possible to call this 099 * method on an uninitialized group implementation instance in order 100 * to determine whether the group implementation would be able to 101 * use the provided configuration. 102 * <BR><BR> 103 * Note that implementations which use a subclass of the provided 104 * configuration class will likely need to cast the configuration 105 * to the appropriate subclass type. 106 * 107 * @param configuration The group implementation 108 * configuration for which to make the 109 * determination. 110 * @param unacceptableReasons A list that may be used to hold the 111 * reasons that the provided 112 * configuration is not acceptable. 113 * 114 * @return {@code true} if the provided configuration is acceptable 115 * for this group implementation, or {@code false} if not. 116 */ 117 public boolean isConfigurationAcceptable( 118 GroupImplementationCfg configuration, 119 List<LocalizableMessage> unacceptableReasons) 120 { 121 // This default implementation does not perform any special 122 // validation. It should be overridden by group implementations 123 // that wish to perform more detailed validation. 124 return true; 125 } 126 127 128 129 /** 130 * Performs any necessary finalization that may be needed whenever 131 * this group implementation is taken out of service within the 132 * Directory Server (e.g., if it is disabled or the server is 133 * shutting down). 134 */ 135 public void finalizeGroupImplementation() 136 { 137 // No implementation is required by default. 138 } 139 140 141 142 /** 143 * Creates a new group of this type based on the definition 144 * contained in the provided entry. This method must be designed so 145 * that it may be invoked on the "shell" instance created using the 146 * default constructor and initialized with the 147 * {@code initializeGroupImplementation} method. 148 * 149 * @param serverContext 150 * The server context. 151 * @param groupEntry The entry containing the definition for the 152 * group to be created. 153 * 154 * @return The group instance created from the definition in the 155 * provided entry. 156 * 157 * @throws DirectoryException If a problem occurs while trying to 158 * create the group instance. 159 */ 160 public abstract Group<T> newInstance(ServerContext serverContext, Entry groupEntry) 161 throws DirectoryException; 162 163 164 165 /** 166 * Retrieves a search filter that may be used to identify entries 167 * containing definitions for groups of this type in the Directory 168 * Server. This method must be designed so that it may be invoked 169 * on the "shell" instance created using the default constructor and 170 * initialized with the {@code initializeGroupImplementation} 171 * method. 172 * 173 * @return A search filter that may be used to identify entries 174 * containing definitions for groups of this type in the 175 * Directory Server. 176 * 177 * @throws DirectoryException If a problem occurs while trying to 178 * locate all of the applicable group 179 * definition entries. 180 */ 181 public abstract SearchFilter getGroupDefinitionFilter() 182 throws DirectoryException; 183 184 185 186 /** 187 * Indicates whether the provided entry contains a valid definition 188 * for this type of group. 189 * 190 * @param entry The entry for which to make the determination. 191 * 192 * @return {@code true} if the provided entry does contain a valid 193 * definition for this type of group, or {@code false} if 194 * it does not. 195 */ 196 public abstract boolean isGroupDefinition(Entry entry); 197 198 199 200 /** 201 * Retrieves the DN of the entry that contains the definition for 202 * this group. 203 * 204 * @return The DN of the entry that contains the definition for 205 * this group. 206 */ 207 public abstract DN getGroupDN(); 208 209 210 211 /** 212 * Sets the DN of the entry that contains the definition for 213 * this group. 214 * 215 * @param groupDN The DN of the entry that contains the 216 * definition for this group. 217 */ 218 public abstract void setGroupDN(DN groupDN); 219 220 221 222 /** 223 * Indicates whether this group supports nesting other groups, such 224 * that the members of the nested groups will also be considered 225 * members of this group. 226 * 227 * @return {@code true} if this group supports nesting other 228 * groups, or {@code false} if it does not. 229 */ 230 public abstract boolean supportsNestedGroups(); 231 232 233 234 /** 235 * Retrieves a list of the DNs of any nested groups whose members 236 * should be considered members of this group. 237 * 238 * @return A list of the DNs of any nested groups whose members 239 * should be considered members of this group. 240 */ 241 public abstract List<DN> getNestedGroupDNs(); 242 243 244 245 /** 246 * Attempts to add the provided group DN as a nested group within 247 * this group. The change should be committed to persistent storage 248 * through an internal operation. 249 * 250 * @param nestedGroupDN The DN of the group that should be added 251 * to the set of nested groups for this 252 * group. 253 * 254 * @throws UnsupportedOperationException If this group does not 255 * support nesting. 256 * 257 * @throws DirectoryException If a problem occurs while attempting 258 * to nest the provided group DN. 259 */ 260 public abstract void addNestedGroup(DN nestedGroupDN) 261 throws UnsupportedOperationException, DirectoryException; 262 263 264 265 /** 266 * Attempts to remove the provided group as a nested group within 267 * this group. The change should be committed to persistent storage 268 * through an internal operation. 269 * 270 * @param nestedGroupDN The DN of the group that should be removed 271 * from the set of nested groups for this 272 * group. 273 * 274 * @throws UnsupportedOperationException If this group does not 275 * support nesting. 276 * 277 * @throws DirectoryException If a problem occurs while attempting 278 * to nest the provided group DN. 279 */ 280 public abstract void removeNestedGroup(DN nestedGroupDN) 281 throws UnsupportedOperationException, DirectoryException; 282 283 284 285 /** 286 * Indicates whether the user with the specified DN is a member of 287 * this group. Note that this is a point-in-time determination and 288 * the caller must not cache the result. 289 * 290 * @param userDN The DN of the user for which to make the 291 * determination. 292 * 293 * @return {@code true} if the specified user is currently a member 294 * of this group, or {@code false} if not. 295 * 296 * @throws DirectoryException If a problem occurs while attempting 297 * to make the determination. 298 */ 299 public boolean isMember(DN userDN) throws DirectoryException 300 { 301 return userDN != null && isMember(userDN, new HashSet<DN>()); 302 } 303 304 305 306 /** 307 * Indicates whether the user with the specified DN is a member of 308 * this group. Note that this is a point-in-time determination and 309 * the caller must not cache the result. Also note that group 310 * implementations that support nesting should use this version of 311 * the method rather than the version that does not take a set of 312 * DNs when attempting to determine whether a nested group includes 313 * the target member. 314 * 315 * @param userDN The DN of the user for which to make the 316 * determination. 317 * @param examinedGroups A set of groups that have already been 318 * examined in the process of making the 319 * determination. This provides a mechanism 320 * to prevent infinite recursion due to 321 * circular references (e.g., two groups 322 * include each other as nested groups). 323 * Each time a group instance is checked, 324 * its DN should be added to the list, and 325 * any DN already contained in the list 326 * should be skipped. 327 * 328 * @return {@code true} if the specified user is currently a member 329 * of this group, or {@code false} if not. 330 * 331 * @throws DirectoryException If a problem occurs while attempting 332 * to make the determination. 333 */ 334 public abstract boolean isMember(DN userDN, Set<DN> examinedGroups) 335 throws DirectoryException; 336 337 338 339 /** 340 * Indicates whether the user described by the provided user entry 341 * is a member of this group. Note that this is a point-in-time 342 * determination and the caller must not cache the result. 343 * 344 * @param userEntry The entry for the user for which to make the 345 * determination. 346 * 347 * @return {@code true} if the specified user is currently a member 348 * of this group, or {@code false} if not. 349 * 350 * @throws DirectoryException If a problem occurs while attempting 351 * to make the determination. 352 */ 353 public boolean isMember(Entry userEntry) 354 throws DirectoryException 355 { 356 return isMember(userEntry, new HashSet<DN>()); 357 } 358 359 360 361 /** 362 * Indicates whether the user described by the provided user entry 363 * is a member of this group. Note that this is a point-in-time 364 * determination and the caller must not cache the result. Also 365 * note that group implementations that support nesting should use 366 * this version of the method rather than the version that does not 367 * take a set of DNs when attempting to determine whether a nested 368 * group includes the target member. 369 * 370 * @param userEntry The entry for the user for which to make 371 * the determination. 372 * @param examinedGroups A set of groups that have already been 373 * examined in the process of making the 374 * determination. This provides a mechanism 375 * to prevent infinite recursion due to 376 * circular references (e.g., two groups 377 * include each other as nested groups). 378 * Each time a group instance is checked, 379 * its DN should be added to the list, and 380 * any DN already contained in the list 381 * should be skipped. 382 * 383 * @return {@code true} if the specified user is currently a member 384 * of this group, or {@code false} if not. 385 * 386 * @throws DirectoryException If a problem occurs while attempting 387 * to make the determination. 388 */ 389 public abstract boolean isMember(Entry userEntry, 390 Set<DN> examinedGroups) 391 throws DirectoryException; 392 393 394 395 /** 396 * Retrieves an iterator that may be used to cursor through the 397 * entries of the members contained in this group. Note that this 398 * is a point-in-time determination, and the caller must not cache 399 * the result. Further, the determination should only include this 400 * group and not members from nested groups. 401 * 402 * @return An iterator that may be used to cursor through the 403 * entries of the members contained in this group. 404 * 405 * @throws DirectoryException If a problem occurs while attempting 406 * to retrieve the set of members. 407 */ 408 public MemberList getMembers() 409 throws DirectoryException 410 { 411 return getMembers(null, null, null); 412 } 413 414 415 416 /** 417 * Retrieves an iterator that may be used to cursor through the 418 * entries of the members contained in this group. It may 419 * optionally retrieve a subset of the member entries based on a 420 * given set of criteria. Note that this is a point-in-time 421 * determination, and the caller must not cache the result. 422 * 423 * @param baseDN The base DN that should be used when determining 424 * whether a given entry will be returned. If this 425 * is {@code null}, then all entries will be 426 * considered in the scope of the criteria. 427 * @param scope The scope that should be used when determining 428 * whether a given entry will be returned. It must 429 * not be {@code null} if the provided base DN is 430 * not {@code null}. The scope will be ignored if 431 * no base DN is provided. 432 * @param filter The filter that should be used when determining 433 * whether a given entry will be returned. If this 434 * is {@code null}, then any entry in the scope of 435 * the criteria will be included in the results. 436 * 437 * @return An iterator that may be used to cursor through the 438 * entries of the members contained in this group. 439 * 440 * @throws DirectoryException If a problem occurs while attempting 441 * to retrieve the set of members. 442 */ 443 public abstract MemberList getMembers(DN baseDN, SearchScope scope, 444 SearchFilter filter) 445 throws DirectoryException; 446 447 448 449 /** 450 * Indicates whether it is possible to alter the member list for 451 * this group (e.g., in order to add members to the group or remove 452 * members from it). 453 * 454 * @return {@code true} if it is possible to add members to this 455 * group, or {@code false} if not. 456 */ 457 public abstract boolean mayAlterMemberList(); 458 459 460 461 /** 462 * Attempts to add the provided user as a member of this group. The 463 * change should be committed to persistent storage through an 464 * internal operation. 465 * 466 * @param userEntry The entry for the user to be added as a member 467 * of this group. 468 * 469 * @throws UnsupportedOperationException If this group does not 470 * support altering the 471 * member list. 472 * 473 * @throws DirectoryException If a problem occurs while attempting 474 * to add the provided user as a member 475 * of this group. 476 */ 477 public abstract void addMember(Entry userEntry) 478 throws UnsupportedOperationException, DirectoryException; 479 480 481 482 /** 483 * Attempts to remove the specified user as a member of this group. 484 * The change should be committed to persistent storage through an 485 * internal operation. 486 * 487 * @param userDN The DN of the user to remove as a member of this 488 * group. 489 * 490 * @throws UnsupportedOperationException If this group does not 491 * support altering the 492 * member list. 493 * 494 * @throws DirectoryException If a problem occurs while attempting 495 * to remove the provided user as a 496 * member of this group. 497 */ 498 public abstract void removeMember(DN userDN) 499 throws UnsupportedOperationException, DirectoryException; 500 501 502 503 /** 504 * Retrieves a string representation of this group. 505 * 506 * @return A string representation of this group. 507 */ 508 public String toString() 509 { 510 StringBuilder buffer = new StringBuilder(); 511 toString(buffer); 512 return buffer.toString(); 513 } 514 515 516 517 /** 518 * Appends a string representation of this group to the provided 519 * buffer. 520 * 521 * @param buffer The buffer to which the string representation 522 * should be appended. 523 */ 524 public abstract void toString(StringBuilder buffer); 525} 526