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