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.Collection;
032 import java.util.LinkedHashSet;
033 import java.util.List;
034
035 import org.opends.server.admin.std.server.EntryDNVirtualAttributeCfg;
036 import org.opends.server.api.VirtualAttributeProvider;
037 import org.opends.server.config.ConfigException;
038 import org.opends.server.core.DirectoryServer;
039 import org.opends.server.core.SearchOperation;
040 import org.opends.server.loggers.debug.DebugTracer;
041 import org.opends.server.types.AttributeType;
042 import org.opends.server.types.AttributeValue;
043 import org.opends.server.types.ByteString;
044 import org.opends.server.types.ByteStringFactory;
045 import org.opends.server.types.ConditionResult;
046 import org.opends.server.types.DebugLogLevel;
047 import org.opends.server.types.DN;
048 import org.opends.server.types.Entry;
049 import org.opends.server.types.InitializationException;
050 import org.opends.server.types.SearchFilter;
051 import org.opends.server.types.SearchScope;
052 import org.opends.server.types.VirtualAttributeRule;
053
054 import static org.opends.server.loggers.debug.DebugLogger.*;
055 import static org.opends.server.util.ServerConstants.*;
056
057
058
059 /**
060 * This class implements a virtual attribute provider that is meant to serve the
061 * entryDN operational attribute as described in draft-zeilenga-ldap-entrydn.
062 */
063 public class EntryDNVirtualAttributeProvider
064 extends VirtualAttributeProvider<EntryDNVirtualAttributeCfg>
065 {
066 /**
067 * The tracer object for the debug logger.
068 */
069 private static final DebugTracer TRACER = getTracer();
070
071 /**
072 * Creates a new instance of this entryDN virtual attribute provider.
073 */
074 public EntryDNVirtualAttributeProvider()
075 {
076 super();
077
078 // All initialization should be performed in the
079 // initializeVirtualAttributeProvider method.
080 }
081
082
083
084 /**
085 * {@inheritDoc}
086 */
087 @Override()
088 public void initializeVirtualAttributeProvider(
089 EntryDNVirtualAttributeCfg configuration)
090 throws ConfigException, InitializationException
091 {
092 // No initialization is required.
093 }
094
095
096
097 /**
098 * {@inheritDoc}
099 */
100 @Override()
101 public boolean isMultiValued()
102 {
103 return false;
104 }
105
106
107
108 /**
109 * {@inheritDoc}
110 */
111 @Override()
112 public LinkedHashSet<AttributeValue> getValues(Entry entry,
113 VirtualAttributeRule rule)
114 {
115 LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
116
117 String normDNString = entry.getDN().toNormalizedString();
118 values.add(new AttributeValue(ByteStringFactory.create(normDNString),
119 ByteStringFactory.create(normDNString)));
120
121 return values;
122 }
123
124
125
126 /**
127 * {@inheritDoc}
128 */
129 @Override()
130 public boolean hasValue(Entry entry, VirtualAttributeRule rule)
131 {
132 // This virtual attribute provider will always generate a value.
133 return true;
134 }
135
136
137
138 /**
139 * {@inheritDoc}
140 */
141 @Override()
142 public boolean hasValue(Entry entry, VirtualAttributeRule rule,
143 AttributeValue value)
144 {
145 try
146 {
147 String normalizedDN = entry.getDN().toNormalizedString();
148 String normalizedValue = value.getNormalizedStringValue();
149 return normalizedDN.equals(normalizedValue);
150 }
151 catch (Exception e)
152 {
153 if (debugEnabled())
154 {
155 TRACER.debugCaught(DebugLogLevel.ERROR, e);
156 }
157
158 return false;
159 }
160 }
161
162
163
164 /**
165 * {@inheritDoc}
166 */
167 @Override()
168 public boolean hasAnyValue(Entry entry, VirtualAttributeRule rule,
169 Collection<AttributeValue> values)
170 {
171 String ndnString = entry.getDN().toNormalizedString();
172
173 AttributeValue v = new AttributeValue(ByteStringFactory.create(ndnString),
174 ByteStringFactory.create(ndnString));
175 return values.contains(v);
176 }
177
178
179
180 /**
181 * {@inheritDoc}
182 */
183 @Override()
184 public ConditionResult matchesSubstring(Entry entry,
185 VirtualAttributeRule rule,
186 ByteString subInitial,
187 List<ByteString> subAny,
188 ByteString subFinal)
189 {
190 // DNs cannot be used in substring matching.
191 return ConditionResult.UNDEFINED;
192 }
193
194
195
196 /**
197 * {@inheritDoc}
198 */
199 @Override()
200 public ConditionResult greaterThanOrEqualTo(Entry entry,
201 VirtualAttributeRule rule,
202 AttributeValue value)
203 {
204 // DNs cannot be used in ordering matching.
205 return ConditionResult.UNDEFINED;
206 }
207
208
209
210 /**
211 * {@inheritDoc}
212 */
213 @Override()
214 public ConditionResult lessThanOrEqualTo(Entry entry,
215 VirtualAttributeRule rule,
216 AttributeValue value)
217 {
218 // DNs cannot be used in ordering matching.
219 return ConditionResult.UNDEFINED;
220 }
221
222
223
224 /**
225 * {@inheritDoc}
226 */
227 @Override()
228 public ConditionResult approximatelyEqualTo(Entry entry,
229 VirtualAttributeRule rule,
230 AttributeValue value)
231 {
232 // DNs cannot be used in approximate matching.
233 return ConditionResult.UNDEFINED;
234 }
235
236
237
238 /**
239 * {@inheritDoc}. This virtual attribute will support search operations only
240 * if one of the following is true about the search filter:
241 * <UL>
242 * <LI>It is an equality filter targeting the associated attribute
243 * type.</LI>
244 * <LI>It is an AND filter in which at least one of the components is an
245 * equality filter targeting the associated attribute type.</LI>
246 * <LI>It is an OR filter in which all of the components are equality
247 * filters targeting the associated attribute type.</LI>
248 * </UL>
249 */
250 @Override()
251 public boolean isSearchable(VirtualAttributeRule rule,
252 SearchOperation searchOperation)
253 {
254 return isSearchable(rule.getAttributeType(), searchOperation.getFilter(),
255 0);
256 }
257
258
259
260
261 /**
262 * Indicates whether the provided search filter is one that may be used with
263 * this virtual attribute provider, optionally operating in a recursive manner
264 * to make the determination.
265 *
266 * @param attributeType The attribute type used to hold the entryDN value.
267 * @param searchFilter The search filter for which to make the
268 * determination.
269 * @param depth The current recursion depth for this processing.
270 *
271 * @return {@code true} if the provided filter may be used with this virtual
272 * attribute provider, or {@code false} if not.
273 */
274 private boolean isSearchable(AttributeType attributeType, SearchFilter filter,
275 int depth)
276 {
277 switch (filter.getFilterType())
278 {
279 case AND:
280 if (depth >= MAX_NESTED_FILTER_DEPTH)
281 {
282 return false;
283 }
284
285 for (SearchFilter f : filter.getFilterComponents())
286 {
287 if (isSearchable(attributeType, f, depth+1))
288 {
289 return true;
290 }
291 }
292 return false;
293
294 case OR:
295 if (depth >= MAX_NESTED_FILTER_DEPTH)
296 {
297 return false;
298 }
299
300 for (SearchFilter f : filter.getFilterComponents())
301 {
302 if (! isSearchable(attributeType, f, depth+1))
303 {
304 return false;
305 }
306 }
307 return true;
308
309 case EQUALITY:
310 return filter.getAttributeType().equals(attributeType);
311
312 default:
313 return false;
314 }
315 }
316
317
318
319 /**
320 * {@inheritDoc}
321 */
322 @Override()
323 public void processSearch(VirtualAttributeRule rule,
324 SearchOperation searchOperation)
325 {
326 SearchFilter filter = searchOperation.getFilter();
327 LinkedHashSet<DN> dnSet = new LinkedHashSet<DN>();
328 extractDNs(rule.getAttributeType(), filter, dnSet);
329
330 if (dnSet.isEmpty())
331 {
332 return;
333 }
334
335 DN baseDN = searchOperation.getBaseDN();
336 SearchScope scope = searchOperation.getScope();
337 for (DN dn : dnSet)
338 {
339 if (! dn.matchesBaseAndScope(baseDN, scope))
340 {
341 continue;
342 }
343
344 try
345 {
346 Entry entry = DirectoryServer.getEntry(dn);
347 if ((entry != null) && filter.matchesEntry(entry))
348 {
349 searchOperation.returnEntry(entry, null);
350 }
351 }
352 catch (Exception e)
353 {
354 if (debugEnabled())
355 {
356 TRACER.debugCaught(DebugLogLevel.ERROR, e);
357 }
358 }
359 }
360 }
361
362
363
364 /**
365 * Extracts the user DNs from the provided filter, operating recursively as
366 * necessary, and adds them to the provided set.
367 *
368 * @param attributeType The attribute type holding the entryDN value.
369 * @param filter The search filter to be processed.
370 * @param dnSet The set into which the identified DNs should be
371 * placed.
372 */
373 private void extractDNs(AttributeType attributeType, SearchFilter filter,
374 LinkedHashSet<DN> dnSet)
375 {
376 switch (filter.getFilterType())
377 {
378 case AND:
379 case OR:
380 for (SearchFilter f : filter.getFilterComponents())
381 {
382 extractDNs(attributeType, f, dnSet);
383 }
384 break;
385
386 case EQUALITY:
387 if (filter.getAttributeType().equals(attributeType))
388 {
389 try
390 {
391 dnSet.add(DN.decode(filter.getAssertionValue().getValue()));
392 }
393 catch (Exception e)
394 {
395 if (debugEnabled())
396 {
397 TRACER.debugCaught(DebugLogLevel.ERROR, e);
398 }
399 }
400 }
401 break;
402 }
403 }
404 }
405