mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Jean-Noel Rouvignac
04.02.2014 da62427f3da608acc65cea059cff0232d7980727
OPENDJ-1602 (CR-5566) New pluggable storage based backend

Decoupled EntryIDSetSorter from EntryContainer.


EntryContainer.java:
Extracted method getEntry(EntryID).

EntryIDSetSorter.java:
Used SuffixContainer.getEntry() instead of using ID2Entry from the jeb package.
Used foreach loops.

SuffixContainer.java:
Added getEntry(EntryID).
Moved ATTR_DEBUG_SEARCH_INDEX here from EntryContainer.

AciHandler.java:
Now reference ATTR_DEBUG_SEARCH_INDEX from SuffixContainer.
Code cleanup.
4 files modified
308 ■■■■■ changed files
opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/AciHandler.java 150 ●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java 101 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java 37 ●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java 20 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -43,7 +43,7 @@
import org.opends.server.api.AccessControlHandler;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConfigHandler;
import org.opends.server.backends.jeb.EntryContainer;
import org.opends.server.backends.pluggable.SuffixContainer;
import org.opends.server.controls.GetEffectiveRightsRequestControl;
import org.opends.server.core.*;
import org.opends.server.protocols.internal.InternalClientConnection;
@@ -64,8 +64,7 @@
import static org.opends.server.util.StaticUtils.*;
/**
 * The AciHandler class performs the main processing for the dseecompat
 * package.
 * The AciHandler class performs the main processing for the dseecompat package.
 */
public final class AciHandler extends
    AccessControlHandler<DseeCompatAccessControlHandlerCfg>
@@ -80,8 +79,7 @@
   * String used to indicate that the evaluating ACI had a all user
   * attributes targetattr match (targetattr="*").
   */
  public static final String ALL_USER_ATTRS_MATCHED =
      "allUserAttrsMatched";
  public static final String ALL_USER_ATTRS_MATCHED = "allUserAttrsMatched";
  /**
   * String used to save the original authorization entry in an
@@ -89,25 +87,16 @@
   */
  public static final String ORIG_AUTH_ENTRY = "origAuthorizationEntry";
  /**
   * Attribute type corresponding to "aci" attribute.
   */
  /** Attribute type corresponding to "aci" attribute. */
  static AttributeType aciType;
  /**
   * Attribute type corresponding to global "ds-cfg-global-aci"
   * attribute.
   */
  /** Attribute type corresponding to global "ds-cfg-global-aci" attribute. */
  static AttributeType globalAciType;
  /**
   * Attribute type corresponding to "debugsearchindex" attribute.
   */
  /** Attribute type corresponding to "debugsearchindex" attribute. */
  private static AttributeType debugSearchIndex;
  /**
   * DN corresponding to "debugsearchindex" attribute type.
   */
  /** DN corresponding to "debugsearchindex" attribute type. */
  private static DN debugSearchIndexDN;
  /**
@@ -132,7 +121,7 @@
  {
    aciType = getAttributeType("aci");
    globalAciType = getAttributeType(ATTR_AUTHZ_GLOBAL_ACI);
    debugSearchIndex = getAttributeType(EntryContainer.ATTR_DEBUG_SEARCH_INDEX);
    debugSearchIndex = getAttributeType(SuffixContainer.ATTR_DEBUG_SEARCH_INDEX);
    refAttrType = getAttributeType(ATTR_REFERRAL_URL);
    try
@@ -157,35 +146,23 @@
  /**
   * The list that holds that ACIs keyed by the DN of the entry holding
   * the ACI.
   */
  /** The list that holds that ACIs keyed by the DN of the entry holding the ACI. */
  private AciList aciList;
  /**
   * The listener that handles ACI changes caused by LDAP operations,
   * ACI decode failure alert logging and backend initialization ACI
   * list adjustment.
   * ACI decode failure alert logging and backend initialization ACI list adjustment.
   */
  private AciListenerManager aciListenerMgr;
  /**
   * Creates a new DSEE-compatible access control handler.
   */
  /** Creates a new DSEE-compatible access control handler. */
  public AciHandler()
  {
    // No implementation required. All initialization should be done in
    // the intializeAccessControlHandler method.
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public void filterEntry(Operation operation,
      SearchResultEntry unfilteredEntry, SearchResultEntry filteredEntry)
@@ -211,12 +188,8 @@
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  /** {@inheritDoc} */
  @Override
  public void finalizeAccessControlHandler()
  {
    aciListenerMgr.finalizeListenerManager();
@@ -224,12 +197,8 @@
    DirectoryServer.deregisterSupportedControl(OID_GET_EFFECTIVE_RIGHTS);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  /** {@inheritDoc} */
  @Override
  public void initializeAccessControlHandler(
      DseeCompatAccessControlHandlerCfg configuration)
      throws ConfigException, InitializationException
@@ -243,11 +212,7 @@
    DirectoryServer.registerSupportedControl(OID_GET_EFFECTIVE_RIGHTS);
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean isAllowed(DN entryDN, Operation op, Control control)
      throws DirectoryException
@@ -286,11 +251,7 @@
    return true;
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean isAllowed(ExtendedOperation operation)
  {
@@ -305,33 +266,19 @@
    return accessAllowed(container);
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean isAllowed(LocalBackendAddOperation operation)
      throws DirectoryException
  {
    AciContainer container =
        new AciLDAPOperationContainer(operation, ACI_ADD);
    if (!isAllowed(container, operation))
    {
      return false;
    }
    // LDAP add needs a verify ACI syntax step in case any
    // "aci" attribute types are being added.
    return verifySyntax(operation.getEntryToAdd(), operation, container
        .getClientDN());
    AciContainer container = new AciLDAPOperationContainer(operation, ACI_ADD);
    return isAllowed(container, operation)
        // LDAP add needs a verify ACI syntax step in case any
        // "aci" attribute types are being added.
        && verifySyntax(operation.getEntryToAdd(), operation, container.getClientDN());
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean isAllowed(BindOperation bindOperation)
  {
@@ -428,9 +375,8 @@
    // original entry DN has export access.
    if (rdnChangesAllowed && newSuperiorDN != null)
    {
      AciContainer container =
          new AciLDAPOperationContainer(operation, ACI_EXPORT, operation
              .getOriginalEntry());
      AciContainer container = new AciLDAPOperationContainer(
          operation, ACI_EXPORT, operation.getOriginalEntry());
      if (!oldRDN.equals(newRDN))
      {
        // The RDNs are not equal, skip the proxy check since it was
@@ -442,11 +388,7 @@
    return rdnChangesAllowed;
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean isAllowed(LocalBackendModifyOperation operation)
      throws DirectoryException
@@ -455,11 +397,7 @@
    return aciCheckMods(container, operation, skipAccessCheck(operation));
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean isAllowed(SearchOperation searchOperation)
  {
@@ -467,11 +405,7 @@
    return true;
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean isAllowed(Operation operation, Entry entry,
      SearchFilter filter) throws DirectoryException
@@ -486,14 +420,9 @@
    return testFilter(container, filter);
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean mayProxy(Entry proxyUser, Entry proxiedUser,
      Operation op)
  public boolean mayProxy(Entry proxyUser, Entry proxiedUser, Operation op)
  {
    if (skipAccessCheck(proxyUser))
    {
@@ -508,14 +437,9 @@
    return accessAllowedEntry(container);
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean maySend(DN dn, Operation operation,
      SearchResultReference reference)
  public boolean maySend(DN dn, Operation operation, SearchResultReference reference)
  {
    if (skipAccessCheck(operation))
    {
@@ -541,11 +465,7 @@
    return accessAllowed(container);
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public boolean maySend(Operation operation, SearchResultEntry entry)
  {
opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -90,8 +90,6 @@
  private static final String REFERRAL_DATABASE_NAME = REFERRAL_INDEX_NAME;
  /** The name of the state database. */
  private static final String STATE_DATABASE_NAME = STATE_INDEX_NAME;
  /** The attribute used to return a search index debug string to the client. */
  public static final String ATTR_DEBUG_SEARCH_INDEX = "debugsearchindex";
  /** The attribute index configuration manager. */
  private final AttributeJEIndexCfgManager attributeJEIndexCfgManager;
@@ -769,8 +767,7 @@
      searchOperation.setResultCode(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
      return;
    }
    VLVRequestControl vlvRequest = searchOperation
    .getRequestControl(VLVRequestControl.DECODER);
    VLVRequestControl vlvRequest = searchOperation.getRequestControl(VLVRequestControl.DECODER);
    if (vlvRequest != null && pageRequest != null)
    {
@@ -889,8 +886,7 @@
        {
          LocalizableMessage message = ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(aBaseDN);
          DN matchedDN = getMatchedDN(aBaseDN);
          throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
              message, matchedDN, null);
          throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message, matchedDN, null);
        }
        DatabaseEntry baseIDData = baseID.getDatabaseEntry();
@@ -940,11 +936,11 @@
            else
            {
              /*
                There is no sort key associated with the sort control. Since it
                came here it means that the criticality is false so let the
                server return all search results unsorted and include the
                sortKeyResponseControl in the searchResultDone message.
              */
               * There is no sort key associated with the sort control. Since it
               * came here it means that the criticality is false so let the
               * server return all search results unsorted and include the
               * sortKeyResponseControl in the searchResultDone message.
               */
              searchOperation.addResponseControl(new ServerSideSortResponseControl(NO_SUCH_ATTRIBUTE, null));
            }
          }
@@ -1018,8 +1014,7 @@
        if (sortRequest.isCritical())
        {
          LocalizableMessage message = ERR_JEB_SEARCH_CANNOT_SORT_UNINDEXED.get();
          throw new DirectoryException(
              ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, message);
          throw new DirectoryException(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, message);
        }
      }
@@ -1048,7 +1043,6 @@
  private void searchNotIndexed(SearchOperation searchOperation, PagedResultsControl pageRequest)
      throws DirectoryException, CanceledOperationException
  {
    EntryCache<?> entryCache = DirectoryServer.getEntryCache();
    DN aBaseDN = searchOperation.getBaseDN();
    SearchScope searchScope = searchOperation.getScope();
    boolean manageDsaIT = isManageDsaITOperation(searchOperation);
@@ -1171,20 +1165,8 @@
                  || findDNKeyParent(key.getData(), 0, key.getSize()) == baseDNKey.length;
          if (isInScope)
          {
            // Try the entry cache first.
            final Entry cacheEntry = entryCache.getEntry(backend, entryID.longValue());
            final Entry entry;
            if (cacheEntry != null)
            {
              entry = cacheEntry;
            }
            else
            {
              entry = id2entry.get(null, entryID, LockMode.DEFAULT);
            }
            // Process the candidate entry.
            final Entry entry = getEntry(entryID);
            if (entry != null)
            {
              lookthroughCount++;
@@ -1238,6 +1220,28 @@
    }
  }
  /** {@inheritDoc} */
  @Override
  public Entry getEntry(EntryID entryID) throws DirectoryException
  {
    // Try the entry cache first.
    final EntryCache entryCache = getEntryCache();
    final Entry cacheEntry = entryCache.getEntry(backend, entryID.longValue());
    if (cacheEntry != null)
    {
      return cacheEntry;
    }
    final Entry entry = id2entry.get(null, entryID, LockMode.DEFAULT);
    if (entry != null)
    {
      // Put the entry in the cache making sure not to overwrite a newer copy
      // that may have been inserted since the time we read the cache.
      entryCache.putEntryIfAbsent(entry, backend, entryID.longValue());
    }
    return entry;
  }
  /**
   * We were able to obtain a set of candidate entry IDs for the
   * search from the indexes.
@@ -1266,7 +1270,6 @@
      PagedResultsControl pageRequest)
  throws DirectoryException, CanceledOperationException
  {
    EntryCache<?> entryCache = DirectoryServer.getEntryCache();
    SearchScope searchScope = searchOperation.getScope();
    DN aBaseDN = searchOperation.getBaseDN();
    boolean manageDsaIT = isManageDsaITOperation(searchOperation);
@@ -1315,49 +1318,27 @@
      {
        final EntryID id = it.next();
        // Try the entry cache first.
        Entry entry;
        Entry cacheEntry = entryCache.getEntry(backend, id.longValue());
        if (cacheEntry == null)
        try
        {
          // Fetch the candidate entry from the database.
          try
          {
            entry = id2entry.get(null, id, LockMode.DEFAULT);
          }
          catch (Exception e)
          {
            logger.traceException(e);
            continue;
          }
          entry = getEntry(id);
        }
        else
        catch (Exception e)
        {
          entry = cacheEntry;
          logger.traceException(e);
          continue;
        }
        // Process the candidate entry.
        if (entry != null)
        {
          boolean isInScope = isInScope(candidatesAreInScope, searchScope, aBaseDN, entry);
          // Put this entry in the cache if it did not come from the cache.
          if (cacheEntry == null)
          {
            // Put the entry in the cache making sure not to overwrite
            // a newer copy that may have been inserted since the time
            // we read the cache.
            entryCache.putEntryIfAbsent(entry, backend, id.longValue());
          }
          // Filter the entry if it is in scope.
          if (isInScope
          if (isInScope(candidatesAreInScope, searchScope, aBaseDN, entry)
              && (manageDsaIT || entry.getReferralURLs() == null)
              && searchOperation.getFilter().matchesEntry(entry))
          {
            if (pageRequest != null &&
                searchOperation.getEntriesSent() ==
                pageRequest.getSize())
            if (pageRequest != null
                && searchOperation.getEntriesSent() == pageRequest.getSize())
            {
              // The current page is full.
              // Set the cookie to remember where we were.
@@ -1384,8 +1365,8 @@
    // Before we return success from the search we must ensure the base entry
    // exists. However, if we have returned at least one entry or subordinate
    // reference it implies the base does exist, so we can omit the check.
    if (searchOperation.getEntriesSent() == 0 &&
        searchOperation.getReferencesSent() == 0)
    if (searchOperation.getEntriesSent() == 0
        && searchOperation.getReferencesSent() == 0)
    {
      // Fetch the base entry if it exists.
      Entry baseEntry = fetchBaseEntry(aBaseDN, searchScope);
opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
@@ -35,6 +35,7 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.backends.pluggable.SuffixContainer;
import org.opends.server.controls.VLVRequestControl;
import org.opends.server.controls.VLVResponseControl;
import org.opends.server.core.DirectoryServer;
@@ -42,8 +43,6 @@
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.types.*;
import com.sleepycat.je.LockMode;
import static org.opends.messages.JebMessages.*;
import static org.opends.server.util.StaticUtils.*;
@@ -57,8 +56,7 @@
   * Creates a new entry ID set which is a sorted representation of the provided
   * set using the given sort order.
   *
   * @param  entryContainer   The entry container with which the ID list is
   *                          associated.
   * @param  suffixContainer  The suffix container with which the ID list is associated.
   * @param  entryIDSet       The entry ID set to be sorted.
   * @param  searchOperation  The search operation being processed.
   * @param  sortOrder        The sort order to use for the entry ID set.
@@ -70,7 +68,7 @@
   *
   * @throws  DirectoryException  If an error occurs while performing the sort.
   */
  public static EntryIDSet sort(EntryContainer entryContainer,
  public static EntryIDSet sort(SuffixContainer suffixContainer,
                                EntryIDSet entryIDSet,
                                SearchOperation searchOperation,
                                SortOrder sortOrder,
@@ -82,7 +80,6 @@
      return new EntryIDSet();
    }
    ID2Entry id2Entry = entryContainer.getID2Entry();
    DN baseDN = searchOperation.getBaseDN();
    SearchScope scope = searchOperation.getScope();
    SearchFilter filter = searchOperation.getFilter();
@@ -92,15 +89,11 @@
    {
      try
      {
        Entry e = id2Entry.get(null, id, LockMode.DEFAULT);
        if ((! e.matchesBaseAndScope(baseDN, scope)) ||
            (! filter.matchesEntry(e)))
        Entry e = suffixContainer.getEntry(id);
        if (e.matchesBaseAndScope(baseDN, scope) && filter.matchesEntry(e))
        {
          continue;
          sortMap.put(new SortValues(id, e, sortOrder), id);
        }
        sortMap.put(new SortValues(id, e, sortOrder), id);
      }
      catch (Exception e)
      {
@@ -111,8 +104,7 @@
    // See if there is a VLV request to further pare down the set of results,
    // and if there is where it should be processed by offset or assertion
    // value.
    // and if there is where it should be processed by offset or assertion value.
    long[] sortedIDs;
    if (vlvRequest != null)
    {
@@ -124,8 +116,7 @@
        int targetOffset = vlvRequest.getOffset();
        if (targetOffset < 0)
        {
          // The client specified a negative target offset.  This should never
          // be allowed.
          // The client specified a negative target offset.  This should never be allowed.
          searchOperation.addResponseControl(
               new VLVResponseControl(targetOffset, sortMap.size(),
                                      LDAPResultCode.OFFSET_RANGE_ERROR));
@@ -167,10 +158,8 @@
        int treePos = 0;
        int arrayPos = 0;
        Iterator<EntryID> idIterator = sortMap.values().iterator();
        while (idIterator.hasNext())
        for (EntryID id : sortMap.values())
        {
          EntryID id = idIterator.next();
          if (treePos++ < startPos)
          {
            continue;
@@ -206,11 +195,8 @@
        int includedAfterCount  = 0;
        int listSize            = 0;
        LinkedList<EntryID> idList = new LinkedList<EntryID>();
        Iterator<Map.Entry<SortValues,EntryID>> mapIterator =
             sortMap.entrySet().iterator();
        while (mapIterator.hasNext())
        for (Map.Entry<SortValues, EntryID> entry : sortMap.entrySet())
        {
          Map.Entry<SortValues,EntryID> entry = mapIterator.next();
          SortValues sortValues = entry.getKey();
          EntryID id = entry.getValue();
@@ -226,7 +212,7 @@
          }
          else
          {
            targetFound = (sortValues.compareTo(assertionValue) >= 0);
            targetFound = sortValues.compareTo(assertionValue) >= 0;
            targetOffset++;
            if (targetFound)
@@ -283,4 +269,3 @@
    return new EntryIDSet(sortedIDs, 0, sortedIDs.length);
  }
}
opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
@@ -26,7 +26,10 @@
import java.io.Closeable;
import org.opends.server.backends.jeb.EntryID;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
/**
 * Container for a whole suffix environment which stores all entries from the
@@ -50,12 +53,13 @@
  String ID2ENTRY_INDEX_NAME = "id2entry";
  /**
   * The name of the index associating an entry id to the entry id set of all
   * its children.
   * its children, i.e. its immediate children.
   */
  String ID2CHILDREN_INDEX_NAME = "id2children";
  /**
   * The name of the index associating an entry id to the entry id set of all
   * its subordinates.
   * its subordinates, i.e. the children, grand-children, grand-grand-children,
   * ....
   */
  String ID2SUBTREE_INDEX_NAME = "id2subtree";
  /** The name of the index associating normalized DNs to normalized URIs. */
@@ -65,6 +69,8 @@
   * does the index needs to be rebuilt ?
   */
  String STATE_INDEX_NAME = "state";
  /** The attribute used to return a search index debug string to the client. */
  String ATTR_DEBUG_SEARCH_INDEX = "debugsearchindex";
  /**
   * Returns the baseDN that this suffix container is responsible for.
@@ -81,4 +87,14 @@
   */
  long getEntryCount();
  /**
   * Returns the entry corresponding to the provided entryID.
   *
   * @param entryID
   *          the id of the entry to retrieve
   * @return the entry corresponding to the provided entryID
   * @throws DirectoryException
   *           If an error occurs retrieving the entry
   */
  Entry getEntry(EntryID entryID) throws DirectoryException;
}