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-2016 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.forgerock.opendj.server.config.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  /** Creates a new instance of this NumSubordinates virtual attribute provider. */
046  public NumSubordinatesVirtualAttributeProvider()
047  {
048    super();
049
050    // All initialization should be performed in the
051    // initializeVirtualAttributeProvider method.
052  }
053
054  @Override
055  public boolean isMultiValued()
056  {
057    return false;
058  }
059
060  @Override
061  public Attribute getValues(Entry entry, VirtualAttributeRule rule)
062  {
063    Backend backend = DirectoryServer.getBackend(entry.getName());
064
065    try
066    {
067      long count = backend.getNumberOfChildren(entry.getName());
068      if(count >= 0)
069      {
070        return Attributes.create(rule.getAttributeType(), String.valueOf(count));
071      }
072    }
073    catch(DirectoryException de)
074    {
075      logger.traceException(de);
076    }
077
078    return Attributes.empty(rule.getAttributeType());
079  }
080
081  @Override
082  public boolean hasValue(Entry entry, VirtualAttributeRule rule)
083  {
084    Backend<?> backend = DirectoryServer.getBackend(entry.getName());
085
086    try
087    {
088       return backend.getNumberOfChildren(entry.getName()) >= 0;
089    }
090    catch(DirectoryException de)
091    {
092      logger.traceException(de);
093      return false;
094    }
095  }
096
097  @Override
098  public boolean hasValue(Entry entry, VirtualAttributeRule rule, ByteString value)
099  {
100    Backend<?> backend = DirectoryServer.getBackend(entry.getName());
101    try
102    {
103      long count = backend.getNumberOfChildren(entry.getName());
104      return count >= 0 && Long.parseLong(value.toString()) == count;
105    }
106    catch (NumberFormatException | DirectoryException e)
107    {
108      logger.traceException(e);
109      return false;
110    }
111  }
112
113  @Override
114  public ConditionResult matchesSubstring(Entry entry,
115                                          VirtualAttributeRule rule,
116                                          ByteString subInitial,
117                                          List<ByteString> subAny,
118                                          ByteString subFinal)
119  {
120    // This virtual attribute does not support substring matching.
121    return ConditionResult.UNDEFINED;
122  }
123
124  @Override
125  public ConditionResult approximatelyEqualTo(Entry entry,
126                              VirtualAttributeRule rule,
127                              ByteString value)
128  {
129    // This virtual attribute does not support approximate matching.
130    return ConditionResult.UNDEFINED;
131  }
132
133  @Override
134  public boolean isSearchable(VirtualAttributeRule rule,
135                              SearchOperation searchOperation,
136                              boolean isPreIndexed)
137  {
138    return false;
139  }
140
141  @Override
142  public void processSearch(VirtualAttributeRule rule,
143                            SearchOperation searchOperation)
144  {
145    searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
146
147    LocalizableMessage message = ERR_NUMSUBORDINATES_VATTR_NOT_SEARCHABLE.get(
148            rule.getAttributeType().getNameOrOID());
149    searchOperation.appendErrorMessage(message);
150  }
151}