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.HasSubordinatesVirtualAttributeCfg;
037import org.opends.server.api.Backend;
038import org.forgerock.opendj.ldap.schema.MatchingRule;
039import org.opends.server.api.VirtualAttributeProvider;
040import org.opends.server.core.DirectoryServer;
041import org.opends.server.core.SearchOperation;
042import org.opends.server.types.*;
043
044import static org.opends.messages.ExtensionMessages.*;
045
046/**
047 * This class implements a virtual attribute provider that is meant to serve the
048 * hasSubordinates operational attribute as described in X.501.
049 */
050public class HasSubordinatesVirtualAttributeProvider
051       extends VirtualAttributeProvider<HasSubordinatesVirtualAttributeCfg>
052{
053  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
054
055  /**
056   * Creates a new instance of this HasSubordinates virtual attribute provider.
057   */
058  public HasSubordinatesVirtualAttributeProvider()
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      ConditionResult ret = backend.hasSubordinates(entry.getName());
082      if(ret != null && ret != ConditionResult.UNDEFINED)
083      {
084        return Attributes.create(rule.getAttributeType(), ret.toString());
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      ConditionResult ret = backend.hasSubordinates(entry.getName());
104      return ret != null && ret != ConditionResult.UNDEFINED;
105    }
106    catch(DirectoryException de)
107    {
108      logger.traceException(de);
109
110      return false;
111    }
112  }
113
114  /** {@inheritDoc} */
115  @Override
116  public boolean hasValue(Entry entry, VirtualAttributeRule rule, ByteString value)
117  {
118    Backend backend = DirectoryServer.getBackend(entry.getName());
119    MatchingRule matchingRule =
120        rule.getAttributeType().getEqualityMatchingRule();
121
122    try
123    {
124      ByteString normValue = matchingRule.normalizeAttributeValue(value);
125      ConditionResult ret = backend.hasSubordinates(entry.getName());
126      return ret != null
127          && ret != ConditionResult.UNDEFINED
128          && ConditionResult.valueOf(normValue.toString()).equals(ret);
129    }
130    catch (Exception de)
131    {
132      logger.traceException(de);
133      return false;
134    }
135  }
136
137  /** {@inheritDoc} */
138  @Override
139  public ConditionResult matchesSubstring(Entry entry,
140                                          VirtualAttributeRule rule,
141                                          ByteString subInitial,
142                                          List<ByteString> subAny,
143                                          ByteString subFinal)
144  {
145    // This virtual attribute does not support substring matching.
146    return ConditionResult.UNDEFINED;
147  }
148
149  /** {@inheritDoc} */
150  @Override
151  public ConditionResult greaterThanOrEqualTo(Entry entry,
152                              VirtualAttributeRule rule,
153                              ByteString value)
154  {
155    // This virtual attribute does not support ordering matching.
156    return ConditionResult.UNDEFINED;
157  }
158
159  /** {@inheritDoc} */
160  @Override
161  public ConditionResult lessThanOrEqualTo(Entry entry,
162                              VirtualAttributeRule rule,
163                              ByteString value)
164  {
165    // This virtual attribute does not support ordering matching.
166    return ConditionResult.UNDEFINED;
167  }
168
169  /** {@inheritDoc} */
170  @Override
171  public ConditionResult approximatelyEqualTo(Entry entry,
172                              VirtualAttributeRule rule,
173                              ByteString value)
174  {
175    // This virtual attribute does not support approximate matching.
176    return ConditionResult.UNDEFINED;
177  }
178
179  /** {@inheritDoc} */
180  @Override
181  public boolean isSearchable(VirtualAttributeRule rule,
182                              SearchOperation searchOperation,
183                              boolean isPreIndexed)
184  {
185    return false;
186  }
187
188  /** {@inheritDoc} */
189  @Override
190  public void processSearch(VirtualAttributeRule rule,
191                            SearchOperation searchOperation)
192  {
193    searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
194
195    LocalizableMessage message = ERR_HASSUBORDINATES_VATTR_NOT_SEARCHABLE.get(
196            rule.getAttributeType().getNameOrOID());
197    searchOperation.appendErrorMessage(message);
198  }
199}
200