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