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