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