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