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