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