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    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.Collection;
033    import java.util.LinkedHashSet;
034    import java.util.List;
035    
036    import org.opends.server.admin.server.ConfigurationChangeListener;
037    import org.opends.server.admin.std.server.MemberVirtualAttributeCfg;
038    import org.opends.server.api.Group;
039    import org.opends.server.api.VirtualAttributeProvider;
040    import org.opends.server.config.ConfigException;
041    import org.opends.server.core.DirectoryServer;
042    import org.opends.server.core.SearchOperation;
043    import org.opends.server.types.AttributeType;
044    import org.opends.server.types.AttributeValue;
045    import org.opends.server.types.ByteString;
046    import org.opends.server.types.ConditionResult;
047    import org.opends.server.types.ConfigChangeResult;
048    import org.opends.server.types.DebugLogLevel;
049    import org.opends.server.types.DN;
050    import org.opends.server.types.Entry;
051    import org.opends.server.types.InitializationException;
052    import org.opends.server.types.MemberList;
053    import org.opends.server.types.MembershipException;
054    import org.opends.server.types.ResultCode;
055    import org.opends.server.types.VirtualAttributeRule;
056    
057    import static org.opends.server.loggers.debug.DebugLogger.*;
058    import org.opends.server.loggers.debug.DebugTracer;
059    import static org.opends.server.util.ServerConstants.*;
060    
061    
062    
063    /**
064     * This class implements a virtual attribute provider that works in conjunction
065     * with virtual static groups to generate the values for the member or
066     * uniqueMember attribute.
067     */
068    public class MemberVirtualAttributeProvider
069           extends VirtualAttributeProvider<MemberVirtualAttributeCfg>
070           implements ConfigurationChangeListener<MemberVirtualAttributeCfg>
071    {
072      /**
073       * The tracer object for the debug logger.
074       */
075      private static final DebugTracer TRACER = getTracer();
076    
077      // The attribute type used to indicate which target group should be used to
078      // obtain the member list.
079      private AttributeType targetGroupType;
080    
081      // The current configuration for this member virtual attribute.
082      private MemberVirtualAttributeCfg currentConfig;
083    
084    
085    
086      /**
087       * Creates a new instance of this member virtual attribute provider.
088       */
089      public MemberVirtualAttributeProvider()
090      {
091        super();
092    
093        // All initialization should be performed in the
094        // initializeVirtualAttributeProvider method.
095      }
096    
097    
098    
099      /**
100       * {@inheritDoc}
101       */
102      @Override()
103      public void initializeVirtualAttributeProvider(
104                                MemberVirtualAttributeCfg configuration)
105             throws ConfigException, InitializationException
106      {
107        configuration.addMemberChangeListener(this);
108        currentConfig = configuration;
109    
110        targetGroupType =
111             DirectoryServer.getAttributeType(ATTR_TARGET_GROUP_DN, true);
112      }
113    
114    
115    
116      /**
117       * {@inheritDoc}
118       */
119      @Override()
120      public boolean isMultiValued()
121      {
122        return true;
123      }
124    
125    
126    
127      /**
128       * {@inheritDoc}
129       */
130      @Override()
131      public LinkedHashSet<AttributeValue> getValues(Entry entry,
132                                                     VirtualAttributeRule rule)
133      {
134        if (! currentConfig.isAllowRetrievingMembership())
135        {
136          return new LinkedHashSet<AttributeValue>(0);
137        }
138    
139        Group g = DirectoryServer.getGroupManager().getGroupInstance(entry.getDN());
140        if (g == null)
141        {
142          return new LinkedHashSet<AttributeValue>(0);
143        }
144    
145        LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
146        try
147        {
148          MemberList memberList = g.getMembers();
149          while (memberList.hasMoreMembers())
150          {
151            try
152            {
153              DN memberDN = memberList.nextMemberDN();
154              if (memberDN != null)
155              {
156                values.add(new AttributeValue(rule.getAttributeType(),
157                                              memberDN.toString()));
158              }
159            }
160            catch (MembershipException me)
161            {
162              if (! me.continueIterating())
163              {
164                break;
165              }
166            }
167          }
168        }
169        catch (Exception e)
170        {
171          if (debugEnabled())
172          {
173            TRACER.debugCaught(DebugLogLevel.ERROR, e);
174          }
175        }
176    
177        return values;
178      }
179    
180    
181    
182      /**
183       * {@inheritDoc}
184       */
185      @Override()
186      public boolean hasValue(Entry entry, VirtualAttributeRule rule)
187      {
188        Group g = DirectoryServer.getGroupManager().getGroupInstance(entry.getDN());
189        if (g == null)
190        {
191          return false;
192        }
193    
194        try
195        {
196          MemberList memberList = g.getMembers();
197          while (memberList.hasMoreMembers())
198          {
199            try
200            {
201              DN memberDN = memberList.nextMemberDN();
202              if (memberDN != null)
203              {
204                memberList.close();
205                return true;
206              }
207            }
208            catch (MembershipException me)
209            {
210              if (! me.continueIterating())
211              {
212                break;
213              }
214            }
215          }
216        }
217        catch (Exception e)
218        {
219          if (debugEnabled())
220          {
221            TRACER.debugCaught(DebugLogLevel.ERROR, e);
222          }
223        }
224    
225        return false;
226      }
227    
228    
229    
230      /**
231       * {@inheritDoc}
232       */
233      @Override()
234      public boolean hasValue(Entry entry, VirtualAttributeRule rule,
235                              AttributeValue value)
236      {
237        Group g = DirectoryServer.getGroupManager().getGroupInstance(entry.getDN());
238        if (g == null)
239        {
240          return false;
241        }
242    
243        try
244        {
245          return g.isMember(DN.decode(value.getValue()));
246        }
247        catch (Exception e)
248        {
249          if (debugEnabled())
250          {
251            TRACER.debugCaught(DebugLogLevel.ERROR, e);
252          }
253        }
254    
255        return false;
256      }
257    
258    
259    
260      /**
261       * {@inheritDoc}
262       */
263      @Override()
264      public boolean hasAnyValue(Entry entry, VirtualAttributeRule rule,
265                                 Collection<AttributeValue> values)
266      {
267        for (AttributeValue v : values)
268        {
269          if (hasValue(entry, rule, v))
270          {
271            return true;
272          }
273        }
274    
275        return false;
276      }
277    
278    
279    
280      /**
281       * {@inheritDoc}
282       */
283      @Override()
284      public ConditionResult matchesSubstring(Entry entry,
285                                              VirtualAttributeRule rule,
286                                              ByteString subInitial,
287                                              List<ByteString> subAny,
288                                              ByteString subFinal)
289      {
290        // DNs cannot be used in substring matching.
291        return ConditionResult.UNDEFINED;
292      }
293    
294    
295    
296      /**
297       * {@inheritDoc}
298       */
299      @Override()
300      public ConditionResult greaterThanOrEqualTo(Entry entry,
301                                  VirtualAttributeRule rule,
302                                  AttributeValue value)
303      {
304        // DNs cannot be used in ordering matching.
305        return ConditionResult.UNDEFINED;
306      }
307    
308    
309    
310      /**
311       * {@inheritDoc}
312       */
313      @Override()
314      public ConditionResult lessThanOrEqualTo(Entry entry,
315                                  VirtualAttributeRule rule,
316                                  AttributeValue value)
317      {
318        // DNs cannot be used in ordering matching.
319        return ConditionResult.UNDEFINED;
320      }
321    
322    
323    
324      /**
325       * {@inheritDoc}
326       */
327      @Override()
328      public ConditionResult approximatelyEqualTo(Entry entry,
329                                  VirtualAttributeRule rule,
330                                  AttributeValue value)
331      {
332        // DNs cannot be used in approximate matching.
333        return ConditionResult.UNDEFINED;
334      }
335    
336    
337    
338      /**
339       * {@inheritDoc}.
340       */
341      @Override()
342      public boolean isSearchable(VirtualAttributeRule rule,
343                                  SearchOperation searchOperation)
344      {
345        return false;
346      }
347    
348    
349    
350      /**
351       * {@inheritDoc}
352       */
353      @Override()
354      public void processSearch(VirtualAttributeRule rule,
355                                SearchOperation searchOperation)
356      {
357        searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
358        return;
359      }
360    
361    
362    
363      /**
364       * {@inheritDoc}
365       */
366      public boolean isConfigurationChangeAcceptable(
367                          MemberVirtualAttributeCfg configuration,
368                          List<Message> unacceptableReasons)
369      {
370        // The new configuration should always be acceptable.
371        return true;
372      }
373    
374    
375    
376      /**
377       * {@inheritDoc}
378       */
379      public ConfigChangeResult applyConfigurationChange(
380                                     MemberVirtualAttributeCfg configuration)
381      {
382        // Just accept the new configuration as-is.
383        currentConfig = configuration;
384    
385        return new ConfigChangeResult(ResultCode.SUCCESS, false);
386      }
387    }
388