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 legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2008-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2012-2015 ForgeRock AS
026 */
027package org.opends.server.extensions;
028
029import java.util.List;
030
031import org.forgerock.i18n.LocalizableMessage;
032import org.forgerock.i18n.slf4j.LocalizedLogger;
033import org.forgerock.opendj.ldap.ByteString;
034import org.forgerock.opendj.ldap.ConditionResult;
035import org.forgerock.opendj.ldap.ResultCode;
036import org.opends.server.admin.std.server.NumSubordinatesVirtualAttributeCfg;
037import org.opends.server.api.Backend;
038import org.opends.server.api.VirtualAttributeProvider;
039import org.opends.server.core.DirectoryServer;
040import org.opends.server.core.SearchOperation;
041import org.opends.server.types.*;
042
043import static org.opends.messages.ExtensionMessages.*;
044
045/**
046 * This class implements a virtual attribute provider that is meant to serve the
047 * hasSubordinates operational attribute as described in
048 * draft-ietf-boreham-numsubordinates.
049 */
050public class NumSubordinatesVirtualAttributeProvider
051    extends VirtualAttributeProvider<NumSubordinatesVirtualAttributeCfg>
052{
053  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
054
055  /**
056   * Creates a new instance of this NumSubordinates virtual attribute provider.
057   */
058  public NumSubordinatesVirtualAttributeProvider()
059  {
060    super();
061
062    // All initialization should be performed in the
063    // initializeVirtualAttributeProvider method.
064  }
065
066  /** {@inheritDoc} */
067  @Override
068  public boolean isMultiValued()
069  {
070    return false;
071  }
072
073  /** {@inheritDoc} */
074  @Override
075  public Attribute getValues(Entry entry, VirtualAttributeRule rule)
076  {
077    Backend backend = DirectoryServer.getBackend(entry.getName());
078
079    try
080    {
081      long count = backend.getNumberOfChildren(entry.getName());
082      if(count >= 0)
083      {
084        return Attributes.create(rule.getAttributeType(), String.valueOf(count));
085      }
086    }
087    catch(DirectoryException de)
088    {
089      logger.traceException(de);
090    }
091
092    return Attributes.empty(rule.getAttributeType());
093  }
094
095  /** {@inheritDoc} */
096  @Override
097  public boolean hasValue(Entry entry, VirtualAttributeRule rule)
098  {
099    Backend<?> backend = DirectoryServer.getBackend(entry.getName());
100
101    try
102    {
103       return backend.getNumberOfChildren(entry.getName()) >= 0;
104    }
105    catch(DirectoryException de)
106    {
107      logger.traceException(de);
108      return false;
109    }
110  }
111
112  /** {@inheritDoc} */
113  @Override
114  public boolean hasValue(Entry entry, VirtualAttributeRule rule, ByteString value)
115  {
116    Backend<?> backend = DirectoryServer.getBackend(entry.getName());
117    try
118    {
119      long count = backend.getNumberOfChildren(entry.getName());
120      return count >= 0 && Long.parseLong(value.toString()) == count;
121    }
122    catch (NumberFormatException | DirectoryException e)
123    {
124      logger.traceException(e);
125      return false;
126    }
127  }
128
129  /** {@inheritDoc} */
130  @Override
131  public ConditionResult matchesSubstring(Entry entry,
132                                          VirtualAttributeRule rule,
133                                          ByteString subInitial,
134                                          List<ByteString> subAny,
135                                          ByteString subFinal)
136  {
137    // This virtual attribute does not support substring matching.
138    return ConditionResult.UNDEFINED;
139  }
140
141  /** {@inheritDoc} */
142  @Override
143  public ConditionResult approximatelyEqualTo(Entry entry,
144                              VirtualAttributeRule rule,
145                              ByteString value)
146  {
147    // This virtual attribute does not support approximate matching.
148    return ConditionResult.UNDEFINED;
149  }
150
151  /** {@inheritDoc} */
152  @Override
153  public boolean isSearchable(VirtualAttributeRule rule,
154                              SearchOperation searchOperation,
155                              boolean isPreIndexed)
156  {
157    return false;
158  }
159
160  /** {@inheritDoc} */
161  @Override
162  public void processSearch(VirtualAttributeRule rule,
163                            SearchOperation searchOperation)
164  {
165    searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
166
167    LocalizableMessage message = ERR_NUMSUBORDINATES_VATTR_NOT_SEARCHABLE.get(
168            rule.getAttributeType().getNameOrOID());
169    searchOperation.appendErrorMessage(message);
170  }
171}
172