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 2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.extensions;
028    
029    
030    
031    import java.util.Collections;
032    import java.util.LinkedHashSet;
033    import java.util.LinkedList;
034    import java.util.List;
035    import java.util.Set;
036    
037    import org.opends.messages.Message;
038    import org.opends.server.admin.std.server.GroupImplementationCfg;
039    import org.opends.server.admin.std.server.StaticGroupImplementationCfg;
040    import org.opends.server.api.Group;
041    import org.opends.server.core.ModifyOperationBasis;
042    import org.opends.server.core.DirectoryServer;
043    import org.opends.server.config.ConfigException;
044    import org.opends.server.loggers.ErrorLogger;
045    import org.opends.server.loggers.debug.DebugTracer;
046    import org.opends.server.protocols.internal.InternalClientConnection;
047    import org.opends.server.types.Attribute;
048    import org.opends.server.types.AttributeType;
049    import org.opends.server.types.AttributeValue;
050    import org.opends.server.types.Control;
051    import org.opends.server.types.DebugLogLevel;
052    import org.opends.server.types.DirectoryConfig;
053    import org.opends.server.types.DirectoryException;
054    import org.opends.server.types.DN;
055    import org.opends.server.types.Entry;
056    import org.opends.server.types.InitializationException;
057    import org.opends.server.types.MemberList;
058    import org.opends.server.types.MembershipException;
059    import org.opends.server.types.Modification;
060    import org.opends.server.types.ModificationType;
061    import org.opends.server.types.ObjectClass;
062    import org.opends.server.types.ResultCode;
063    import org.opends.server.types.SearchFilter;
064    import org.opends.server.types.SearchScope;
065    
066    import static org.opends.messages.ExtensionMessages.*;
067    import static org.opends.server.loggers.debug.DebugLogger.*;
068    import static org.opends.server.util.ServerConstants.*;
069    import static org.opends.server.util.Validator.*;
070    
071    
072    
073    /**
074     * This class provides a static group implementation, in which the DNs
075     * of all members are explicitly listed.  There are two variants of
076     * static groups:  one based on the {@code groupOfNames} object class,
077     * which stores the member list in the {@code member} attribute, and
078     * one based on the {@code groupOfUniqueNames} object class, which
079     * stores the member list in the {@code uniqueMember} attribute.
080     */
081    public class StaticGroup
082           extends Group<StaticGroupImplementationCfg>
083    {
084      /**
085       * The tracer object for the debug logger.
086       */
087      private static final DebugTracer TRACER = getTracer();
088    
089      // The attribute type used to hold the membership list for this group.
090      private AttributeType memberAttributeType;
091    
092      // The DN of the entry that holds the definition for this group.
093      private DN groupEntryDN;
094    
095      // The set of the DNs of the members for this group.
096      private LinkedHashSet<DN> memberDNs;
097    
098      //The list of nested group DNs for this group.
099      private LinkedList<DN> nestedGroups = new LinkedList<DN>();
100    
101      //Passed to the group manager to see if the nested group list needs to be
102      //refreshed.
103      private long nestedGroupRefreshToken =
104                                  DirectoryServer.getGroupManager().refreshToken();
105    
106    
107    
108      /**
109       * Creates a new, uninitialized static group instance.  This is intended for
110       * internal use only.
111       */
112      public StaticGroup()
113      {
114        super();
115    
116    
117        // No initialization is required here.
118      }
119    
120    
121    
122      /**
123       * Creates a new static group instance with the provided information.
124       *
125       * @param  groupEntryDN         The DN of the entry that holds the definition
126       *                              for this group.
127       * @param  memberAttributeType  The attribute type used to hold the membership
128       *                              list for this group.
129       * @param  memberDNs            The set of the DNs of the members for this
130       *                              group.
131       */
132      public StaticGroup(DN groupEntryDN, AttributeType memberAttributeType,
133                         LinkedHashSet<DN> memberDNs)
134      {
135        super();
136    
137    
138        ensureNotNull(groupEntryDN, memberAttributeType, memberDNs);
139    
140        this.groupEntryDN        = groupEntryDN;
141        this.memberAttributeType = memberAttributeType;
142        this.memberDNs           = memberDNs;
143      }
144    
145    
146    
147      /**
148       * {@inheritDoc}
149       */
150      @Override()
151      public void initializeGroupImplementation(
152                       StaticGroupImplementationCfg configuration)
153             throws ConfigException, InitializationException
154      {
155        // No additional initialization is required.
156      }
157    
158    
159    
160    
161      /**
162       * {@inheritDoc}
163       */
164      @Override()
165      public StaticGroup newInstance(Entry groupEntry)
166             throws DirectoryException
167      {
168        ensureNotNull(groupEntry);
169    
170    
171        // Determine whether it is a groupOfNames or groupOfUniqueNames entry.  If
172        // neither, then that's a problem.
173        AttributeType memberAttributeType;
174        ObjectClass groupOfEntriesClass =
175             DirectoryConfig.getObjectClass(OC_GROUP_OF_ENTRIES_LC, true);
176        ObjectClass groupOfNamesClass =
177             DirectoryConfig.getObjectClass(OC_GROUP_OF_NAMES_LC, true);
178        ObjectClass groupOfUniqueNamesClass =
179             DirectoryConfig.getObjectClass(OC_GROUP_OF_UNIQUE_NAMES_LC, true);
180        if (groupEntry.hasObjectClass(groupOfEntriesClass))
181        {
182          if (groupEntry.hasObjectClass(groupOfNamesClass))
183          {
184            Message message = ERR_STATICGROUP_INVALID_OC_COMBINATION.
185                get(String.valueOf(groupEntry.getDN()), OC_GROUP_OF_ENTRIES,
186                    OC_GROUP_OF_NAMES);
187            throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
188          }
189          else if (groupEntry.hasObjectClass(groupOfUniqueNamesClass))
190          {
191            Message message = ERR_STATICGROUP_INVALID_OC_COMBINATION.
192                get(String.valueOf(groupEntry.getDN()), OC_GROUP_OF_ENTRIES,
193                    OC_GROUP_OF_UNIQUE_NAMES);
194            throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
195          }
196    
197          memberAttributeType = DirectoryConfig.getAttributeType(ATTR_MEMBER, true);
198        }
199        else if (groupEntry.hasObjectClass(groupOfNamesClass))
200        {
201          if (groupEntry.hasObjectClass(groupOfUniqueNamesClass))
202          {
203            Message message = ERR_STATICGROUP_INVALID_OC_COMBINATION.
204                get(String.valueOf(groupEntry.getDN()), OC_GROUP_OF_NAMES,
205                    OC_GROUP_OF_UNIQUE_NAMES);
206            throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
207          }
208    
209          memberAttributeType = DirectoryConfig.getAttributeType(ATTR_MEMBER, true);
210        }
211        else if (groupEntry.hasObjectClass(groupOfUniqueNamesClass))
212        {
213          memberAttributeType =
214               DirectoryConfig.getAttributeType(ATTR_UNIQUE_MEMBER_LC, true);
215        }
216        else
217        {
218          Message message = ERR_STATICGROUP_NO_VALID_OC.
219              get(String.valueOf(groupEntry.getDN()), OC_GROUP_OF_NAMES,
220                  OC_GROUP_OF_UNIQUE_NAMES);
221          throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
222        }
223    
224    
225        LinkedHashSet<DN> memberDNs = new LinkedHashSet<DN>();
226        List<Attribute> memberAttrList =
227             groupEntry.getAttribute(memberAttributeType);
228        if (memberAttrList != null)
229        {
230          for (Attribute a : memberAttrList)
231          {
232            for (AttributeValue v : a.getValues())
233            {
234              try
235              {
236                DN memberDN = DN.decode(v.getValue());
237                memberDNs.add(memberDN);
238              }
239              catch (DirectoryException de)
240              {
241                if (debugEnabled())
242                {
243                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
244                }
245    
246                Message message = ERR_STATICGROUP_CANNOT_DECODE_MEMBER_VALUE_AS_DN.
247                    get(v.getStringValue(), memberAttributeType.getNameOrOID(),
248                        String.valueOf(groupEntry.getDN()), de.getMessageObject());
249                ErrorLogger.logError(message);
250              }
251            }
252          }
253        }
254    
255    
256        return new StaticGroup(groupEntry.getDN(), memberAttributeType, memberDNs);
257      }
258    
259    
260    
261      /**
262       * {@inheritDoc}
263       */
264      @Override()
265      public SearchFilter getGroupDefinitionFilter()
266             throws DirectoryException
267      {
268        // FIXME -- This needs to exclude enhanced groups once we have support for
269        // them.
270        String filterString =
271             "(&(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)" +
272                "(objectClass=groupOfEntries))" +
273                "(!(objectClass=ds-virtual-static-group)))";
274        return SearchFilter.createFilterFromString(filterString);
275      }
276    
277    
278    
279      /**
280       * {@inheritDoc}
281       */
282      @Override()
283      public boolean isGroupDefinition(Entry entry)
284      {
285        ensureNotNull(entry);
286    
287        // FIXME -- This needs to exclude enhanced groups once we have support for
288        //them.
289        ObjectClass virtualStaticGroupClass =
290             DirectoryConfig.getObjectClass(OC_VIRTUAL_STATIC_GROUP, true);
291        if (entry.hasObjectClass(virtualStaticGroupClass))
292        {
293          return false;
294        }
295    
296        ObjectClass groupOfEntriesClass =
297             DirectoryConfig.getObjectClass(OC_GROUP_OF_ENTRIES_LC, true);
298        ObjectClass groupOfNamesClass =
299             DirectoryConfig.getObjectClass(OC_GROUP_OF_NAMES_LC, true);
300        ObjectClass groupOfUniqueNamesClass =
301             DirectoryConfig.getObjectClass(OC_GROUP_OF_UNIQUE_NAMES_LC, true);
302        if (entry.hasObjectClass(groupOfEntriesClass))
303        {
304          if (entry.hasObjectClass(groupOfNamesClass) ||
305              entry.hasObjectClass(groupOfUniqueNamesClass))
306          {
307            return false;
308          }
309    
310          return true;
311        }
312        else if (entry.hasObjectClass(groupOfNamesClass))
313        {
314          if (entry.hasObjectClass(groupOfUniqueNamesClass))
315          {
316            return false;
317          }
318    
319          return true;
320        }
321        else if (entry.hasObjectClass(groupOfUniqueNamesClass))
322        {
323          return true;
324        }
325        else
326        {
327          return false;
328        }
329      }
330    
331    
332    
333      /**
334       * {@inheritDoc}
335       */
336      @Override()
337      public DN getGroupDN()
338      {
339        return groupEntryDN;
340      }
341    
342    
343    
344      /**
345       * {@inheritDoc}
346       */
347      @Override()
348      public boolean supportsNestedGroups()
349      {
350        return true;
351      }
352    
353    
354    
355      /**
356       * {@inheritDoc}
357       */
358      @Override()
359      public List<DN> getNestedGroupDNs()
360      {
361        try {
362           reloadIfNeeded();
363        } catch (DirectoryException ex) {
364          return Collections.<DN>emptyList();
365        }
366        return nestedGroups;
367      }
368    
369    
370    
371      /**
372       * {@inheritDoc}
373       */
374      @Override()
375      public void addNestedGroup(DN nestedGroupDN)
376             throws UnsupportedOperationException, DirectoryException
377      {
378         ensureNotNull(nestedGroupDN);
379    
380        synchronized (this)
381        {
382          if (nestedGroups.contains(nestedGroupDN))
383          {
384            Message msg = ERR_STATICGROUP_ADD_NESTED_GROUP_ALREADY_EXISTS.get(
385                    String.valueOf(nestedGroupDN),
386                    String.valueOf(groupEntryDN));
387            throw new DirectoryException(
388                    ResultCode.ATTRIBUTE_OR_VALUE_EXISTS, msg);
389          }
390    
391          LinkedHashSet<AttributeValue> values =
392               new LinkedHashSet<AttributeValue>(1);
393          values.add(new AttributeValue(memberAttributeType,
394                                        nestedGroupDN.toString()));
395    
396          Attribute attr = new Attribute(memberAttributeType,
397                                         memberAttributeType.getNameOrOID(),
398                                         values);
399    
400          LinkedList<Modification> mods = new LinkedList<Modification>();
401          mods.add(new Modification(ModificationType.ADD, attr));
402    
403          LinkedList<Control> requestControls = new LinkedList<Control>();
404          requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
405                                          false));
406    
407          InternalClientConnection conn =
408               InternalClientConnection.getRootConnection();
409          ModifyOperationBasis modifyOperation =
410               new ModifyOperationBasis(conn,
411                       InternalClientConnection.nextOperationID(),
412                       InternalClientConnection.nextMessageID(), requestControls,
413                                   groupEntryDN, mods);
414          modifyOperation.run();
415          if (modifyOperation.getResultCode() != ResultCode.SUCCESS)
416          {
417            Message msg = ERR_STATICGROUP_ADD_MEMBER_UPDATE_FAILED.get(
418                    String.valueOf(nestedGroupDN),
419                    String.valueOf(groupEntryDN),
420                    modifyOperation.getErrorMessage().toString());
421            throw new DirectoryException(modifyOperation.getResultCode(),
422                                         msg);
423          }
424    
425    
426          LinkedList<DN> newNestedGroups = new LinkedList<DN>(nestedGroups);
427          newNestedGroups.add(nestedGroupDN);
428          nestedGroups = newNestedGroups;
429          //Add it to the member DN list.
430          LinkedHashSet<DN> newMemberDNs = new LinkedHashSet<DN>(memberDNs);
431          newMemberDNs.add(nestedGroupDN);
432          memberDNs = newMemberDNs;
433        }
434      }
435    
436    
437    
438      /**
439       * {@inheritDoc}
440       */
441      @Override()
442      public void removeNestedGroup(DN nestedGroupDN)
443             throws UnsupportedOperationException, DirectoryException
444      {
445        ensureNotNull(nestedGroupDN);
446    
447        synchronized (this)
448        {
449          if (! nestedGroups.contains(nestedGroupDN))
450          {
451            throw new DirectoryException(
452                    ResultCode.NO_SUCH_ATTRIBUTE,
453                    ERR_STATICGROUP_REMOVE_NESTED_GROUP_NO_SUCH_GROUP.get(
454                      String.valueOf(nestedGroupDN),
455                      String.valueOf(groupEntryDN)));
456          }
457    
458          LinkedHashSet<AttributeValue> values =
459               new LinkedHashSet<AttributeValue>(1);
460          values.add(new AttributeValue(memberAttributeType,
461                                                         nestedGroupDN.toString()));
462    
463          Attribute attr = new Attribute(memberAttributeType,
464                                         memberAttributeType.getNameOrOID(),
465                                         values);
466    
467          LinkedList<Modification> mods = new LinkedList<Modification>();
468          mods.add(new Modification(ModificationType.DELETE, attr));
469    
470          LinkedList<Control> requestControls = new LinkedList<Control>();
471          requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
472                                          false));
473    
474          InternalClientConnection conn =
475               InternalClientConnection.getRootConnection();
476          ModifyOperationBasis modifyOperation =
477               new ModifyOperationBasis(conn,
478                       InternalClientConnection.nextOperationID(),
479                       InternalClientConnection.nextMessageID(), requestControls,
480                       groupEntryDN, mods);
481          modifyOperation.run();
482          if (modifyOperation.getResultCode() != ResultCode.SUCCESS)
483          {
484            throw new DirectoryException(
485                    modifyOperation.getResultCode(),
486                    ERR_STATICGROUP_REMOVE_MEMBER_UPDATE_FAILED.get(
487                            String.valueOf(nestedGroupDN),
488                            String.valueOf(groupEntryDN),
489                            modifyOperation.getErrorMessage()));
490          }
491    
492    
493          LinkedList<DN> newNestedGroups = new LinkedList<DN>(nestedGroups);
494          newNestedGroups.remove(nestedGroupDN);
495          nestedGroups = newNestedGroups;
496          //Remove it from the member DN list.
497          LinkedHashSet<DN> newMemberDNs = new LinkedHashSet<DN>(memberDNs);
498          newMemberDNs.remove(nestedGroupDN);
499          memberDNs = newMemberDNs;
500        }
501      }
502    
503    
504    
505      /**
506       * {@inheritDoc}
507       */
508      @Override()
509      public boolean isMember(DN userDN, Set<DN> examinedGroups)
510              throws DirectoryException
511      {
512        reloadIfNeeded();
513        if(memberDNs.contains(userDN))
514        {
515          return true;
516        }
517        else if (! examinedGroups.add(getGroupDN()))
518        {
519          return false;
520        }
521        else
522        {
523          for(DN nestedGroupDN : nestedGroups)
524          {
525            Group<? extends GroupImplementationCfg> g =
526                 (Group<? extends GroupImplementationCfg>)
527                  DirectoryServer.getGroupManager().getGroupInstance(nestedGroupDN);
528            if((g != null) && (g.isMember(userDN, examinedGroups)))
529            {
530              return true;
531            }
532          }
533        }
534        return false;
535      }
536    
537    
538    
539      /**
540       * {@inheritDoc}
541       */
542      @Override()
543      public boolean isMember(Entry userEntry, Set<DN> examinedGroups)
544             throws DirectoryException
545      {
546        return isMember(userEntry.getDN(), examinedGroups);
547      }
548    
549    
550    
551      /**
552       * Check if the group manager has registered a new group instance or removed a
553       * a group instance that might impact this group's membership list.
554       */
555      private void
556      reloadIfNeeded() throws DirectoryException
557      {
558        //Check if group instances have changed by passing the group manager
559        //the current token.
560        if(DirectoryServer.getGroupManager().
561                hasInstancesChanged(nestedGroupRefreshToken))
562        {
563          synchronized (this)
564          {
565            Group thisGroup =
566                   DirectoryServer.getGroupManager().getGroupInstance(groupEntryDN);
567            //Check if the group itself has been removed
568            if(thisGroup == null) {
569              throw new DirectoryException(
570                      ResultCode.NO_SUCH_ATTRIBUTE,
571                      ERR_STATICGROUP_GROUP_INSTANCE_INVALID.get(
572                        String.valueOf(groupEntryDN)));
573            } else if(thisGroup != this) {
574              LinkedHashSet<DN> newMemberDNs = new LinkedHashSet<DN>();
575              MemberList memberList=thisGroup.getMembers();
576              while (memberList.hasMoreMembers()) {
577                try {
578                  newMemberDNs.add(memberList.nextMemberDN());
579                } catch (MembershipException ex) {}
580              }
581              memberDNs=newMemberDNs;
582            }
583            LinkedList<DN> newNestedGroups = new LinkedList<DN>();
584            for(DN dn : memberDNs)
585            {
586              Group gr=DirectoryServer.getGroupManager().getGroupInstance(dn);
587              if(gr != null)
588              {
589                newNestedGroups.add(gr.getGroupDN());
590              }
591            }
592            nestedGroupRefreshToken =
593                    DirectoryServer.getGroupManager().refreshToken();
594            nestedGroups=newNestedGroups;
595          }
596        }
597      }
598    
599    
600      /**
601       * {@inheritDoc}
602       */
603      @Override()
604      public MemberList getMembers()
605             throws DirectoryException
606      {
607        reloadIfNeeded();
608        return new SimpleStaticGroupMemberList(groupEntryDN, memberDNs);
609      }
610    
611    
612    
613      /**
614       * {@inheritDoc}
615       */
616      @Override()
617      public MemberList getMembers(DN baseDN, SearchScope scope,
618                                   SearchFilter filter)
619             throws DirectoryException
620      {
621        reloadIfNeeded();
622        if ((baseDN == null) && (filter == null))
623        {
624          return new SimpleStaticGroupMemberList(groupEntryDN, memberDNs);
625        }
626        else
627        {
628          return new FilteredStaticGroupMemberList(groupEntryDN, memberDNs, baseDN,
629                                                   scope, filter);
630        }
631      }
632    
633    
634    
635      /**
636       * {@inheritDoc}
637       */
638      @Override()
639      public boolean mayAlterMemberList()
640      {
641        return true;
642      }
643    
644    
645    
646      /**
647       * {@inheritDoc}
648       */
649      @Override()
650      public void addMember(Entry userEntry)
651             throws UnsupportedOperationException, DirectoryException
652      {
653        ensureNotNull(userEntry);
654    
655        synchronized (this)
656        {
657          DN userDN = userEntry.getDN();
658          if (memberDNs.contains(userDN))
659          {
660            Message message = ERR_STATICGROUP_ADD_MEMBER_ALREADY_EXISTS.get(
661                String.valueOf(userDN), String.valueOf(groupEntryDN));
662            throw new DirectoryException(ResultCode.ATTRIBUTE_OR_VALUE_EXISTS,
663                                         message);
664          }
665    
666          LinkedHashSet<AttributeValue> values =
667               new LinkedHashSet<AttributeValue>(1);
668          values.add(new AttributeValue(memberAttributeType, userDN.toString()));
669    
670          Attribute attr = new Attribute(memberAttributeType,
671                                         memberAttributeType.getNameOrOID(),
672                                         values);
673    
674          LinkedList<Modification> mods = new LinkedList<Modification>();
675          mods.add(new Modification(ModificationType.ADD, attr));
676    
677          LinkedList<Control> requestControls = new LinkedList<Control>();
678          requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
679                                          false));
680    
681          InternalClientConnection conn =
682               InternalClientConnection.getRootConnection();
683          ModifyOperationBasis modifyOperation =
684               new ModifyOperationBasis(conn, conn.nextOperationID(),
685                                   conn.nextMessageID(), requestControls,
686                                   groupEntryDN, mods);
687          modifyOperation.run();
688          if (modifyOperation.getResultCode() != ResultCode.SUCCESS)
689          {
690            Message message = ERR_STATICGROUP_ADD_MEMBER_UPDATE_FAILED.
691                get(String.valueOf(userDN), String.valueOf(groupEntryDN),
692                    modifyOperation.getErrorMessage().toString());
693            throw new DirectoryException(modifyOperation.getResultCode(), message);
694          }
695    
696    
697          LinkedHashSet<DN> newMemberDNs =
698               new LinkedHashSet<DN>(memberDNs.size()+1);
699          newMemberDNs.addAll(memberDNs);
700          newMemberDNs.add(userDN);
701          memberDNs = newMemberDNs;
702        }
703      }
704    
705    
706    
707      /**
708       * {@inheritDoc}
709       */
710      @Override()
711      public void removeMember(DN userDN)
712             throws UnsupportedOperationException, DirectoryException
713      {
714        ensureNotNull(userDN);
715    
716        synchronized (this)
717        {
718          if (! memberDNs.contains(userDN))
719          {
720            Message message = ERR_STATICGROUP_REMOVE_MEMBER_NO_SUCH_MEMBER.get(
721                String.valueOf(userDN), String.valueOf(groupEntryDN));
722            throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE, message);
723          }
724    
725    
726          LinkedHashSet<AttributeValue> values =
727               new LinkedHashSet<AttributeValue>(1);
728          values.add(new AttributeValue(memberAttributeType, userDN.toString()));
729    
730          Attribute attr = new Attribute(memberAttributeType,
731                                         memberAttributeType.getNameOrOID(),
732                                         values);
733    
734          LinkedList<Modification> mods = new LinkedList<Modification>();
735          mods.add(new Modification(ModificationType.DELETE, attr));
736    
737          LinkedList<Control> requestControls = new LinkedList<Control>();
738          requestControls.add(new Control(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE,
739                                          false));
740    
741          InternalClientConnection conn =
742               InternalClientConnection.getRootConnection();
743          ModifyOperationBasis modifyOperation =
744               new ModifyOperationBasis(conn, conn.nextOperationID(),
745                                   conn.nextMessageID(), requestControls,
746                                   groupEntryDN, mods);
747          modifyOperation.run();
748          if (modifyOperation.getResultCode() != ResultCode.SUCCESS)
749          {
750            Message message = ERR_STATICGROUP_REMOVE_MEMBER_UPDATE_FAILED.
751                get(String.valueOf(userDN), String.valueOf(groupEntryDN),
752                    modifyOperation.getErrorMessage().toString());
753            throw new DirectoryException(modifyOperation.getResultCode(), message);
754          }
755    
756    
757          LinkedHashSet<DN> newMemberDNs = new LinkedHashSet<DN>(memberDNs);
758          newMemberDNs.remove(userDN);
759          memberDNs = newMemberDNs;
760          //If it is in the nested group list remove it.
761          if(nestedGroups.contains(userDN)) {
762            LinkedList<DN> newNestedGroups = new LinkedList<DN>(nestedGroups);
763            newNestedGroups.remove(userDN);
764            nestedGroups = newNestedGroups;
765          }
766        }
767      }
768    
769    
770    
771      /**
772       * {@inheritDoc}
773       */
774      @Override()
775      public void toString(StringBuilder buffer)
776      {
777        buffer.append("StaticGroup(");
778        buffer.append(groupEntryDN);
779        buffer.append(")");
780      }
781    }
782