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.LinkedHashSet;
032 import java.util.List;
033
034 import org.opends.messages.Message;
035 import org.opends.server.admin.std.server.NumSubordinatesVirtualAttributeCfg;
036 import org.opends.server.api.VirtualAttributeProvider;
037 import org.opends.server.api.Backend;
038 import org.opends.server.config.ConfigException;
039 import org.opends.server.core.DirectoryServer;
040 import org.opends.server.core.SearchOperation;
041 import org.opends.server.loggers.debug.DebugTracer;
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.DirectoryException;
048 import org.opends.server.types.Entry;
049 import org.opends.server.types.InitializationException;
050 import org.opends.server.types.ResultCode;
051 import org.opends.server.types.VirtualAttributeRule;
052
053 import static org.opends.messages.ExtensionMessages.*;
054 import static org.opends.server.loggers.debug.DebugLogger.getTracer;
055 import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
056
057
058
059 /**
060 * This class implements a virtual attribute provider that is meant to serve the
061 * hasSubordinates operational attribute as described in
062 * draft-ietf-boreham-numsubordinates.
063 */
064 public class NumSubordinatesVirtualAttributeProvider
065 extends VirtualAttributeProvider<NumSubordinatesVirtualAttributeCfg>
066 {
067 /**
068 * The tracer object for the debug logger.
069 */
070 private static final DebugTracer TRACER = getTracer();
071
072 /**
073 * Creates a new instance of this NumSubordinates virtual attribute provider.
074 */
075 public NumSubordinatesVirtualAttributeProvider()
076 {
077 super();
078
079 // All initialization should be performed in the
080 // initializeVirtualAttributeProvider method.
081 }
082
083
084
085 /**
086 * {@inheritDoc}
087 */
088 @Override()
089 public void initializeVirtualAttributeProvider(
090 NumSubordinatesVirtualAttributeCfg configuration)
091 throws ConfigException, InitializationException
092 {
093 // No initialization is required.
094 }
095
096
097
098 /**
099 * {@inheritDoc}
100 */
101 @Override()
102 public boolean isMultiValued()
103 {
104 return false;
105 }
106
107
108
109 /**
110 * {@inheritDoc}
111 */
112 @Override()
113 public LinkedHashSet<AttributeValue> getValues(Entry entry,
114 VirtualAttributeRule rule)
115 {
116 LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
117
118 Backend backend = DirectoryServer.getBackend(entry.getDN());
119
120 try
121 {
122 long count = backend.numSubordinates(entry.getDN(), false);
123 if(count >= 0)
124 {
125 AttributeValue value =
126 new AttributeValue(ByteStringFactory.create(String.valueOf(count)),
127 ByteStringFactory.create(String.valueOf(count)));
128 values.add(value);
129 }
130 }
131 catch(DirectoryException de)
132 {
133 if (debugEnabled())
134 {
135 TRACER.debugCaught(DebugLogLevel.ERROR, de);
136 }
137 }
138
139 return values;
140 }
141
142
143
144 /**
145 * {@inheritDoc}
146 */
147 @Override()
148 public boolean hasValue(Entry entry, VirtualAttributeRule rule)
149 {
150 Backend backend = DirectoryServer.getBackend(entry.getDN());
151
152 try
153 {
154 return backend.numSubordinates(entry.getDN(), false) >= 0;
155 }
156 catch(DirectoryException de)
157 {
158 if (debugEnabled())
159 {
160 TRACER.debugCaught(DebugLogLevel.ERROR, de);
161 }
162
163 return false;
164 }
165 }
166
167
168
169 /**
170 * {@inheritDoc}
171 */
172 @Override()
173 public boolean hasValue(Entry entry, VirtualAttributeRule rule,
174 AttributeValue value)
175 {
176 Backend backend = DirectoryServer.getBackend(entry.getDN());
177
178 try
179 {
180 long count = backend.numSubordinates(entry.getDN(), false);
181 if(count >= 0)
182 {
183 return Long.parseLong(value.getNormalizedStringValue()) == count;
184 }
185 return false;
186 }
187 catch(DirectoryException de)
188 {
189 if (debugEnabled())
190 {
191 TRACER.debugCaught(DebugLogLevel.ERROR, de);
192 }
193
194 return false;
195 }
196 }
197
198
199
200 /**
201 * {@inheritDoc}
202 */
203 @Override()
204 public ConditionResult matchesSubstring(Entry entry,
205 VirtualAttributeRule rule,
206 ByteString subInitial,
207 List<ByteString> subAny,
208 ByteString subFinal)
209 {
210 // This virtual attribute does not support substring matching.
211 return ConditionResult.UNDEFINED;
212 }
213
214
215
216 /**
217 * {@inheritDoc}
218 */
219 @Override()
220 public ConditionResult approximatelyEqualTo(Entry entry,
221 VirtualAttributeRule rule,
222 AttributeValue value)
223 {
224 // This virtual attribute does not support approximate matching.
225 return ConditionResult.UNDEFINED;
226 }
227
228
229
230 /**
231 * {@inheritDoc}. This virtual attribute will support search operations only
232 * if one of the following is true about the search filter:
233 * <UL>
234 * <LI>It is an equality filter targeting the associated attribute
235 * type.</LI>
236 * <LI>It is an AND filter in which at least one of the components is an
237 * equality filter targeting the associated attribute type.</LI>
238 * <LI>It is an OR filter in which all of the components are equality
239 * filters targeting the associated attribute type.</LI>
240 * </UL>
241 */
242 @Override()
243 public boolean isSearchable(VirtualAttributeRule rule,
244 SearchOperation searchOperation)
245 {
246 return false;
247 }
248
249
250
251 /**
252 * {@inheritDoc}
253 */
254 @Override()
255 public void processSearch(VirtualAttributeRule rule,
256 SearchOperation searchOperation)
257 {
258 searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
259
260 Message message = ERR_NUMSUBORDINATES_VATTR_NOT_SEARCHABLE.get(
261 rule.getAttributeType().getNameOrOID());
262 searchOperation.appendErrorMessage(message);
263 }
264 }
265