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