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