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

Jean-Noel Rouvignac
01.23.2014 5d7be546948d1d019e3d29932b222d69412643dd
Code cleanups.



MessageHandler.java:
Extracted method fillLateQueue().

MsgQueue.java:
Added toString().

PersistentServerState.java:
Renamed field baseDn => baseDN.
Made updateStateEntry() return a boolean instead of a ResultCode.
Used Collections.singleton*() methods.
Added toString().



JEReplicaDBCursor.java:
In next(), factorized code.

ExternalChangeLogTest.java:
Inlined a few passthrough test methods.
Renamed createControls() to createCookieControl().
In getControls(), removed an esoteric way to call Assert.fail(). Let the exception bubble up dammit!

InternalSearchMonitorTestCase.java:
Simplified code calling processSearch().
In getMonitorNames(), do not copy the monitor names.


BrowserController.java:
Reduce fields + methods visibilities.
Added final keyword to fields.
Removed unused methods removeSuffix(), showAttributeName(), removeBrowserEventListener(), notifyChildEntryChanged(), notifyChildEntryAdded(), notifyChildEntryDeleted(), startRefresh(), shutDown(), getAttrsForGreenSearch(), entryArrayFromCollection(), nodeArrayFromCollection().
Extracted methods getAciCount(), getNewIcon() and toInt().
Used early returns.

IconPool.java:
Removed unused method maskedIcon().

LDAPConnectionPool.java:
Reduce fields + methods visibilities.
Added final keyword to fields.
Used static import for ConnectionUtils.
Changed makeLDAPUrl() to accept a single InitialLdapContext parameter.
Removed unused methods removeReferralAuthenticationListener(), flush(), getAuthDN(), getAuthPassword(), getRegisteredAuthentication().
9 files modified
1614 ■■■■■ changed files
opends/src/guitools/org/opends/guitools/controlpanel/browser/BrowserController.java 767 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/browser/IconPool.java 116 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/browser/LDAPConnectionPool.java 198 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java 75 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/server/MessageHandler.java 59 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/server/MsgQueue.java 65 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/server/changelog/je/JEReplicaDBCursor.java 19 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java 97 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ExternalChangeLogTest.java 218 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/browser/BrowserController.java
@@ -89,20 +89,20 @@
  /**
   * The mask used to display the number of ACIs or not.
   */
  public final static int DISPLAY_ACI_COUNT        = 0x01;
  private static final int DISPLAY_ACI_COUNT = 0x01;
  /**
   * The list of attributes that are used to sort the entries (if the sorting
   * option is used).
   */
  public static final String[] SORT_ATTRIBUTES = {"cn", "givenname", "o", "ou",
    "sn", "uid"};
  private static final String[] SORT_ATTRIBUTES =
    { "cn", "givenname", "o", "ou", "sn", "uid" };
  /**
   * This is a key value.  It is used to specify that the attribute that should
   * be used to display the entry is the RDN attribute.
   */
  public static final String RDN_ATTRIBUTE = "rdn attribute";
  private static final String RDN_ATTRIBUTE = "rdn attribute";
  /**
   * The filter used to retrieve all the entries.
@@ -110,12 +110,12 @@
  public static final String ALL_OBJECTS_FILTER =
    "(|(objectClass=*)(objectClass=ldapsubentry))";
  private JTree tree;
  private DefaultTreeModel treeModel;
  private RootNode rootNode;
  private final JTree tree;
  private final DefaultTreeModel treeModel;
  private final RootNode rootNode;
  private int displayFlags;
  private String displayAttribute;
  private boolean showAttributeName;
  private final boolean showAttributeName;
  private InitialLdapContext ctxConfiguration;
  private InitialLdapContext ctxUserData;
  private boolean followReferrals;
@@ -127,12 +127,12 @@
  private NumSubordinateHacker numSubordinateHacker;
  private int queueTotalSize;
  private int maxChildren = 0;
  private Collection<BrowserEventListener> listeners =
  private final Collection<BrowserEventListener> listeners =
    new ArrayList<BrowserEventListener>();
  private LDAPConnectionPool connectionPool;
  private IconPool iconPool;
  private final LDAPConnectionPool connectionPool;
  private final IconPool iconPool;
  private NodeSearcherQueue refreshQueue;
  private final NodeSearcherQueue refreshQueue;
  private String filter;
@@ -159,6 +159,7 @@
    tree.addTreeExpansionListener(this);
    tree.setCellRenderer(new BrowserCellRenderer());
    displayFlags = DISPLAY_ACI_COUNT;
    showAttributeName = false;
    displayAttribute = RDN_ATTRIBUTE;
    followReferrals = false;
    sorted = false;
@@ -260,17 +261,16 @@
  }
  /**
   * Tells wether the given suffix is in the tree or not.
   * Tells whether the given suffix is in the tree or not.
   * @param suffixDn the DN of the suffix to be analyzed.
   * @return <CODE>true</CODE> if the provided String is the DN of a suffix
   * and <CODE>false</CODE> otherwise.
   * @throws IllegalArgumentException if a node with the given dn exists but
   * is not a suffix node.
   */
  public boolean hasSuffix(String suffixDn)
  throws IllegalArgumentException
  public boolean hasSuffix(String suffixDn) throws IllegalArgumentException
  {
    return (findSuffixNode(suffixDn, rootNode) != null);
    return findSuffixNode(suffixDn, rootNode) != null;
  }
  /**
@@ -328,28 +328,6 @@
    return new TreePath(treeModel.getPathToRoot(newNode));
  }
  /**
   * Remove the suffix from this controller.
   * The controller updates the JTree and returns the TreePath
   * of the parent node.
   * @param suffixDn the DN of the suffix to be removed.
   * @return the TreePath of the parent node of the removed node.
   */
  public TreePath removeSuffix(String suffixDn) {
    TreePath result = null;
    BasicNode node = findSuffixNode(suffixDn, rootNode);
    TreeNode parentNode = node.getParent();
    /* If the parent is null... the node is no longer in the tree */
    if (parentNode != null) {
      removeOneNode(node);
      result = new TreePath(treeModel.getPathToRoot(parentNode));
    }
    return result;
  }
  /**
   * Remove all the suffixes.
   * The controller removes all the nodes from the JTree except the root.
@@ -403,18 +381,6 @@
  }
  /**
   * Says wether to show the attribute name or not.
   * This routine collapses the JTree and invokes startRefresh().
   * @param showAttributeName whether to show the attribute name or not.
   */
  public void showAttributeName(boolean showAttributeName) {
    this.showAttributeName = showAttributeName;
    stopRefresh();
    removeAllChildNodes(rootNode, true /* Keep suffixes */);
    startRefresh(null);
  }
  /**
   * Says wether we are showing the attribute name or not.
   * @return <CODE>true</CODE> if we are showing the attribute name and
   * <CODE>false</CODE> otherwise.
@@ -586,16 +552,6 @@
    listeners.add(l);
  }
  /**
   * Remove a BrowserEventListener from this controller.
   * @param l the listener to be removed.
   */
  public void removeBrowserEventListener(BrowserEventListener l) {
    listeners.remove(l);
  }
  /**
   * Notify this controller that an entry has been added.
   * The controller adds a new node in the JTree and starts refreshing this new
@@ -635,19 +591,18 @@
   * @return the tree path associated with the parent of the deleted node.
   */
  public TreePath notifyEntryDeleted(BrowserNodeInfo nodeInfo) {
    TreePath result = null;
    BasicNode node = nodeInfo.getNode();
    if (node == rootNode) {
      throw new IllegalArgumentException("Root node cannot be removed");
    }
    TreeNode parentNode = node.getParent();
    /* If the parent is null... the node is no longer in the tree */
    final TreeNode parentNode = node.getParent();
    if (parentNode != null) {
      removeOneNode(node);
      result = new TreePath(treeModel.getPathToRoot(parentNode));
      return new TreePath(treeModel.getPathToRoot(parentNode));
    }
    return result;
    return null;
  }
@@ -663,50 +618,10 @@
  }
  /**
   * Notify this controller that a child entry has changed.
   * The controller has to refresh the corresponding node and (if necessary)
   * itself.
   * @param nodeInfo the parent of the node that changed.
   * @param dn the DN of the entry that changed.
   */
  public void notifyChildEntryChanged(BrowserNodeInfo nodeInfo, String dn) {
    BasicNode node = nodeInfo.getNode();
    startRefreshNode(node, null, true);
  }
  /**
   * Notify this controller that a child entry has been added.
   * The controller has to refresh the corresponding node and (if necessary)
   * itself.
   * @param nodeInfo the parent of the node that was added.
   * @param dn the DN of the entry that was added.
   */
  public void notifyChildEntryAdded(BrowserNodeInfo nodeInfo, String dn) {
    BasicNode node = nodeInfo.getNode();
    startRefreshNode(node, null, true);
  }
  /**
   * Notify this controller that a child entry has been deleted.
   * The controller has to refresh the corresponding node and (if necessary)
   * itself.
   * @param nodeInfo the parent of the node that was deleted.
   * @param dn the DN of the entry that was deleted.
   */
  public void notifyChildEntryDeleted(BrowserNodeInfo nodeInfo, String dn) {
    BasicNode node = nodeInfo.getNode();
    if (node.getParent() != null) {
      startRefreshNode((BasicNode) node.getParent(), null, true);
    } else {
      startRefreshNode(node, null, true);
    }
  }
  /**
   * Notify this controller that authentication data have changed in the
   * connection pool.
   */
  @Override
  public void notifyAuthDataChanged() {
    notifyAuthDataChanged(null);
  }
@@ -718,7 +633,7 @@
   * url.
   * @param url the URL of the connection that changed.
   */
  public void notifyAuthDataChanged(LDAPURL url) {
  private void notifyAuthDataChanged(LDAPURL url) {
    // TODO: temporary implementation
    //    we should refresh only nodes :
    //    - whose URL matches 'url'
@@ -730,7 +645,7 @@
  /**
   * Start a refresh from the specified node.
   * If some refresh are on-going on descendent nodes, they are stopped.
   * If some refresh are on-going on descendant nodes, they are stopped.
   * If nodeInfo is null, refresh is started from the root.
   * @param nodeInfo the node to be refreshed.
   */
@@ -746,35 +661,15 @@
    startRefreshNode(node, null, true);
  }
  /**
   * Equivalent to startRefresh(null).
   */
  public void startRefresh() {
    startRefresh(null);
  }
  /**
   * Stop the current refreshing.
   * Nodes being expanded are collapsed.
   */
  public void stopRefresh() {
  private void stopRefresh() {
    stopRefreshNode(rootNode);
    // TODO: refresh must be stopped in a clean state.
  }
  /**
   * Shutdown the controller : all the backgroup threads are stopped.
   * After this call, the controller is no longer usable.
   */
  public void shutDown() {
    tree.removeTreeExpansionListener(this);
    refreshQueue.shutdown();
    connectionPool.flush();
  }
  /**
   * Start refreshing the whole tree from the specified node.
   * We queue a refresh which:
@@ -784,7 +679,7 @@
   * @param localEntry the local entry corresponding to the node.
   * @param recursive whether the refresh must be executed recursively or not.
   */
  void startRefreshNode(BasicNode node, SearchResult localEntry,
  private void startRefreshNode(BasicNode node, SearchResult localEntry,
      boolean recursive) {
    if (node == rootNode) {
      // For the root node, readBaseEntry is meaningless.
@@ -803,7 +698,7 @@
      // The task does not *see* suffixes.
      // So we need to propagate the refresh on
      // the sub-suffixes if any.
      if (recursive && (node instanceof SuffixNode)) {
      if (recursive && node instanceof SuffixNode) {
        Enumeration<?> e = node.children();
        while (e.hasMoreElements()) {
          BasicNode child = (BasicNode)e.nextElement();
@@ -824,7 +719,7 @@
   * root node.
   * @param node the node where the refresh must stop.
   */
  void stopRefreshNode(BasicNode node) {
  private void stopRefreshNode(BasicNode node) {
    if (node == rootNode) {
      refreshQueue.cancelAll();
    }
@@ -844,11 +739,11 @@
   * Call startRefreshNode() on each referral node accessible from parentNode.
   * @param parentNode the parent node.
   */
  void startRefreshReferralNodes(BasicNode parentNode) {
  private void startRefreshReferralNodes(BasicNode parentNode) {
    Enumeration<?> e = parentNode.children();
    while (e.hasMoreElements()) {
      BasicNode child = (BasicNode)e.nextElement();
      if ((child.getReferral() != null) || (child.getRemoteUrl() != null)) {
      if (child.getReferral() != null || child.getRemoteUrl() != null) {
        startRefreshNode(child, null, true);
      }
      else {
@@ -866,10 +761,10 @@
   * @param parentNode the parent node.
   * @param keepSuffixes whether the suffixes should be kept or not.
   */
  void removeAllChildNodes(BasicNode parentNode, boolean keepSuffixes) {
  private void removeAllChildNodes(BasicNode parentNode, boolean keepSuffixes) {
    for (int i = parentNode.getChildCount() - 1; i >= 0; i--) {
      BasicNode child = (BasicNode)parentNode.getChildAt(i);
      if ((child instanceof SuffixNode) && keepSuffixes) {
      if (child instanceof SuffixNode && keepSuffixes) {
        removeAllChildNodes(child, true);
        child.setRefreshNeededOnExpansion(true);
      }
@@ -885,6 +780,7 @@
   * if it needs it (to search the children for instance).
   * @param event the tree expansion event.
   */
  @Override
  public void treeExpanded(TreeExpansionEvent event) {
    if (!automaticallyExpandedNode)
    {
@@ -904,6 +800,7 @@
   * tasks on it are canceled.
   * @param event the tree collapse event.
   */
  @Override
  public void treeCollapsed(TreeExpansionEvent event) {
    Object node = event.getPath().getLastPathComponent();
    if (!(node instanceof RootNode)) {
@@ -1054,32 +951,19 @@
   * @throws NamingException if there is an error retrieving the connection.
   * @return the LDAP connection to reading the base entry of a node.
   */
  InitialLdapContext findConnectionForLocalEntry(BasicNode node,
      boolean isConfigurationNode)
  throws NamingException {
    InitialLdapContext result;
  private InitialLdapContext findConnectionForLocalEntry(BasicNode node,
      boolean isConfigurationNode) throws NamingException
  {
    if (node == rootNode) {
      result = ctxConfiguration;
      return ctxConfiguration;
    }
    else  {
      BasicNode parent = (BasicNode)node.getParent();
      if ((parent != null) && (parent != rootNode))
      {
        result = findConnectionForDisplayedEntry(parent, isConfigurationNode);
      }
      else
      {
        if (isConfigurationNode)
        {
          result = ctxConfiguration;
        }
        else
        {
          result = ctxUserData;
        }
      }
    final BasicNode parent = (BasicNode) node.getParent();
    if (parent != null && parent != rootNode)
    {
      return findConnectionForDisplayedEntry(parent, isConfigurationNode);
    }
    return result;
    return isConfigurationNode ? ctxConfiguration : ctxUserData;
  }
  /**
@@ -1090,7 +974,6 @@
   */
  public boolean isConfigurationNode(BasicNode node)
  {
    boolean isConfigurationNode = false;
    if (node instanceof SuffixNode)
    {
      String dn = node.getDN();
@@ -1103,12 +986,12 @@
          Utilities.areDnsEqual(dn, ConfigConstants.DN_BACKUP_ROOT) ||
          Utilities.areDnsEqual(dn, ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT))
      {
        isConfigurationNode = true;
        return true;
      }
    }
    else if (node instanceof RootNode)
    {
      isConfigurationNode = true;
      return true;
    }
    else
    {
@@ -1116,7 +999,7 @@
      return isConfigurationNode(parentNode);
    }
    return isConfigurationNode;
    return false;
  }
  /**
@@ -1140,18 +1023,13 @@
   * @return the LDAP connection to search the displayed entry.
   * @throws NamingException if there is an error retrieving the connection.
   */
  InitialLdapContext findConnectionForDisplayedEntry(BasicNode node,
      boolean isConfigurationNode)
  throws NamingException {
    InitialLdapContext result;
    if (followReferrals && (node.getRemoteUrl() != null))
  private InitialLdapContext findConnectionForDisplayedEntry(BasicNode node,
      boolean isConfigurationNode) throws NamingException {
    if (followReferrals && node.getRemoteUrl() != null)
    {
      result = connectionPool.getConnection(node.getRemoteUrl());
      return connectionPool.getConnection(node.getRemoteUrl());
    }
    else {
      result = findConnectionForLocalEntry(node, isConfigurationNode);
    }
    return result;
    return findConnectionForLocalEntry(node, isConfigurationNode);
  }
@@ -1162,8 +1040,7 @@
   * @param ctx the connection to be released.
   */
  void releaseLDAPConnection(InitialLdapContext ctx) {
    if ((ctx != this.ctxConfiguration) &&
        (ctx != this.ctxUserData))
    if (ctx != this.ctxConfiguration && ctx != this.ctxUserData)
    {
      // Thus it comes from the connection pool
      connectionPool.releaseConnection(ctx);
@@ -1177,20 +1054,16 @@
   * @return the local entry URL for a given node.
   */
  LDAPURL findUrlForLocalEntry(BasicNode node) {
    LDAPURL result;
    if (node == rootNode) {
      result = LDAPConnectionPool.makeLDAPUrl(ctxConfiguration, "");
      return LDAPConnectionPool.makeLDAPUrl(ctxConfiguration, "");
    }
    else {
      BasicNode parent = (BasicNode)node.getParent();
      if (parent != null) {
        LDAPURL parentUrl = findUrlForDisplayedEntry(parent);
        result = LDAPConnectionPool.makeLDAPUrl(parentUrl, node.getDN());
      } else {
        result = LDAPConnectionPool.makeLDAPUrl(ctxConfiguration, node.getDN());
      }
    final BasicNode parent = (BasicNode) node.getParent();
    if (parent != null)
    {
      final LDAPURL parentUrl = findUrlForDisplayedEntry(parent);
      return LDAPConnectionPool.makeLDAPUrl(parentUrl, node.getDN());
    }
    return result;
    return LDAPConnectionPool.makeLDAPUrl(ctxConfiguration, node.getDN());
  }
@@ -1199,15 +1072,12 @@
   * @param node the node.
   * @return the displayed entry URL for a given node.
   */
  LDAPURL findUrlForDisplayedEntry(BasicNode node) {
    LDAPURL result;
    if (followReferrals && (node.getRemoteUrl() != null)) {
      result = node.getRemoteUrl();
  private LDAPURL findUrlForDisplayedEntry(BasicNode node)
  {
    if (followReferrals && node.getRemoteUrl() != null) {
      return node.getRemoteUrl();
    }
    else {
      result = findUrlForLocalEntry(node);
    }
    return result;
    return findUrlForLocalEntry(node);
  }
@@ -1221,15 +1091,10 @@
   * @return the DN to use for searching children of a given node.
   */
  String findBaseDNForChildEntries(BasicNode node) {
    String result;
    if (followReferrals && (node.getRemoteUrl() != null)) {
      result = node.getRemoteUrl().getRawBaseDN();
    if (followReferrals && node.getRemoteUrl() != null) {
      return node.getRemoteUrl().getRawBaseDN();
    }
    else {
      result = node.getDN();
    }
    return result;
    return node.getDN();
  }
@@ -1240,24 +1105,20 @@
   * @return <CODE>true</CODE> if the node displays a remote entry and
   * <CODE>false</CODE> otherwise.
   */
  boolean isDisplayedEntryRemote(BasicNode node) {
    boolean result = false;
  private boolean isDisplayedEntryRemote(BasicNode node) {
    if (followReferrals) {
      if (node == rootNode) {
        result = false;
        return false;
      }
      else if (node.getRemoteUrl() != null) {
        result = true;
      if (node.getRemoteUrl() != null) {
        return true;
      }
      else {
        BasicNode parent = (BasicNode)node.getParent();
        if (parent != null) {
          result = isDisplayedEntryRemote(parent);
        }
      final BasicNode parent = (BasicNode)node.getParent();
      if (parent != null) {
        return isDisplayedEntryRemote(parent);
      }
    }
    return result;
    return false;
  }
@@ -1275,30 +1136,11 @@
    if ((displayFlags & DISPLAY_ACI_COUNT) != 0) {
      v.add("aci");
    }
    if (!displayAttribute.equals(RDN_ATTRIBUTE)) {
    if (!RDN_ATTRIBUTE.equals(displayAttribute)) {
      v.add(displayAttribute);
    }
    String[] result = new String[v.size()];
    v.toArray(result);
    return result;
  }
  /**
   * Returns the list of attributes for the green search.
   * @return the list of attributes for the green search.
   */
  String[] getAttrsForGreenSearch() {
    if (!displayAttribute.equals(RDN_ATTRIBUTE)) {
      return new String[] {
          "aci",
          displayAttribute};
    } else {
      return new String[] {
          "aci"
      };
    }
    return v.toArray(new String[v.size()]);
  }
  /**
@@ -1306,7 +1148,7 @@
   * @return the list of attributes for the black search.
   */
  String[] getAttrsForBlackSearch() {
    if (!displayAttribute.equals(RDN_ATTRIBUTE)) {
    if (!RDN_ATTRIBUTE.equals(displayAttribute)) {
      return new String[] {
          "objectClass",
          "numsubordinates",
@@ -1339,7 +1181,7 @@
   * Returns the request controls to search user data.
   * @return the request controls to search user data.
   */
  Control[] getRequestControls()
  private Control[] getRequestControls()
  {
    Control ctls[];
    if (followReferrals)
@@ -1378,7 +1220,7 @@
   * Returns the request controls to search configuration data.
   * @return the request controls to search configuration data.
   */
  Control[] getConfigurationRequestControls()
  private Control[] getConfigurationRequestControls()
  {
    return getRequestControls();
  }
@@ -1430,8 +1272,8 @@
      // tree.
      // Except when it's due a to referral resolution: we keep the node
      // in order the user can fix the referral.
      if (isNameNotFoundException(task.getException()) &&
          (oldState != NodeRefresher.State.SOLVING_REFERRAL)) {
      if (isNameNotFoundException(task.getException())
          && oldState != NodeRefresher.State.SOLVING_REFERRAL) {
        removeOneNode(node);
      }
      else {
@@ -1460,8 +1302,8 @@
        nodeChanged = updateNodeRendering(node, task.getDisplayedEntry());
      }
    }
    else if ((newState == NodeRefresher.State.CANCELLED) &&
        (newState == NodeRefresher.State.INTERRUPTED)) {
    else if (newState == NodeRefresher.State.CANCELLED
        && newState == NodeRefresher.State.INTERRUPTED) {
      // Let's collapse task.getNode()
      tree.collapsePath(new TreePath(treeModel.getPathToRoot(node)));
@@ -1470,8 +1312,8 @@
    }
    else {
      if ((oldState != NodeRefresher.State.SEARCHING_CHILDREN) &&
          (newState == NodeRefresher.State.SEARCHING_CHILDREN)) {
      if (oldState != NodeRefresher.State.SEARCHING_CHILDREN
          && newState == NodeRefresher.State.SEARCHING_CHILDREN) {
        // The children search is going to start
        if (canDoDifferentialUpdate(task)) {
          Enumeration<?> e = node.children();
@@ -1538,11 +1380,9 @@
        }
      }
      if (newState == NodeRefresher.State.FINISHED) {
        if (node.getError() != null) {
          node.setError(null);
          nodeChanged = updateNodeRendering(node, task.getDisplayedEntry());
        }
      if (newState == NodeRefresher.State.FINISHED && node.getError() != null) {
        node.setError(null);
        nodeChanged = updateNodeRendering(node, task.getDisplayedEntry());
      }
    }
@@ -1551,10 +1391,9 @@
      treeModel.nodeChanged(task.getNode());
    }
    if (node.isLeaf() && (node.getChildCount() >= 1)) {
    if (node.isLeaf() && node.getChildCount() >= 1) {
      throw new RuntimeException("Inconsistent node: " + node.getDN());
    }
  }
@@ -1570,8 +1409,8 @@
      final NodeRefresher.State oldState,
      final NodeRefresher.State newState)
  throws InterruptedException {
    Runnable r = new Runnable() {
      @Override
      public void run() {
        try {
          refreshTaskDidProgress(task, oldState, newState);
@@ -1635,13 +1474,13 @@
        child = new BasicNode(entry.getName());
        parent.insert(child, index);
        updateNodeRendering(child, entry);
        insertIndex.add(new Integer(index));
        insertIndex.add(Integer.valueOf(index));
//      System.out.println("Inserted " + child.getDN() + " at " + index);
      }
      else { // Else we update the existing one
        child = (BasicNode)parent.getChildAt(index);
        if (updateNodeRendering(child, entry)) {
          changedIndex.add(new Integer(index));
          changedIndex.add(Integer.valueOf(index));
        }
        // The node is no longer obsolete
        child.setObsolete(false);
@@ -1649,24 +1488,13 @@
      // NUMSUBORDINATE HACK
      // Let's see if child has subordinates or not.
      // Thanks to slapd, we cannot always trust the
      // numSubOrdinates attribute. If the child entry's DN
      // is found in the hacker's list, then we ignore
      // Thanks to slapd, we cannot always trust the numSubOrdinates attribute.
      // If the child entry's DN is found in the hacker's list, then we ignore
      // the numSubordinate attribute... :((
      boolean hasNoSubOrdinates;
      if (!child.hasSubOrdinates() && dontTrust) {
        LDAPURL childUrl = findUrlForDisplayedEntry(child);
        if (numSubordinateHacker.contains(childUrl)) {
          // The numSubOrdinates we have is unreliable.
          // child may potentially have subordinates.
          hasNoSubOrdinates = false;
//        System.out.println("numSubordinates of " + childUrl +
//        " is not reliable");
        }
        else {
          // We can trust this 0 value
          hasNoSubOrdinates = true;
        }
        hasNoSubOrdinates = !numSubordinateHacker.contains(childUrl);
      }
      else {
        hasNoSubOrdinates = !child.hasSubOrdinates();
@@ -1675,7 +1503,7 @@
      // Propagate the refresh
      // Note: logically we should unconditionaly call:
      // Note: logically we should unconditionally call:
      //  startRefreshNode(child, false, true);
      //
      // However doing that saturates refreshQueue
@@ -1691,9 +1519,9 @@
      // node had children (in the tree).  In this case
      // we force the refresh. See bug 5015115
      //
      if (!hasNoSubOrdinates ||
          (child.getReferral() != null) ||
          (child.getChildCount() > 0)) {
      if (!hasNoSubOrdinates
          || child.getReferral() != null
          || child.getChildCount() > 0) {
        startRefreshNode(child, entry, true);
      }
    }
@@ -1711,16 +1539,14 @@
  /**
   * Tells wheter a differential update can be made in the provided task.
   * Tells whether a differential update can be made in the provided task.
   * @param task the task.
   * @return <CODE>true</CODE> if a differential update can be made and
   * <CODE>false</CODE> otherwise.
   */
  private boolean canDoDifferentialUpdate(NodeRefresher task) {
    return (
        (task.getNode().getChildCount() >= 1) &&
        (task.getNode().getNumSubOrdinates() <= 100)
    );
    return task.getNode().getChildCount() >= 1
        && task.getNode().getNumSubOrdinates() <= 100;
  }
@@ -1736,82 +1562,25 @@
    if (entry != null) {
      // Get the numsubordinates
      node.setNumSubOrdinates(getNumSubOrdinates(entry));
      if (node.getNumSubOrdinates() > 0)
      {
        node.setHasSubOrdinates(true);
      }
      else
      {
        // Calculate based also in the hasSubordinates attribute
        node.setHasSubOrdinates(getHasSubOrdinates(entry));
      }
      node.setHasSubOrdinates(
          node.getNumSubOrdinates() > 0 || getHasSubOrdinates(entry));
      node.setReferral(getReferral(entry));
      Set<String> ocValues = ConnectionUtils.getValues(entry, "objectClass");
      if (ocValues != null) {
        String[] array = new String[ocValues.size()];
        ocValues.toArray(array);
        node.setObjectClassValues(array);
        node.setObjectClassValues(ocValues.toArray(new String[ocValues.size()]));
      }
    }
    // Get the aci count
    int aciCount;
    if (((displayFlags & DISPLAY_ACI_COUNT) != 0) && (entry != null)) {
      Set<String> aciValues = ConnectionUtils.getValues(entry, "aci");
      if (aciValues != null) {
        aciCount = aciValues.size();
      }
      else {
        aciCount = 0;
      }
    }
    else {
      aciCount = 0;
    }
    // Select the icon according the objectClass,...
    int modifiers = 0;
    if (node.isLeaf() && !node.hasSubOrdinates()) {
      modifiers |= IconPool.MODIFIER_LEAF;
    }
    if (node.getReferral() != null) {
      modifiers |= IconPool.MODIFIER_REFERRAL;
    }
    if (node.getError() != null) {
      if (node.getError().getException() != null)
      {
        LOG.log(Level.SEVERE, "node has error: "+node.getError().getException(),
            node.getError().getException());
      }
      modifiers |= IconPool.MODIFIER_ERROR;
    }
    SortedSet<String> objectClasses = new TreeSet<String>();
    if (entry != null) {
      Set<String> ocs = ConnectionUtils.getValues(entry, "objectClass");
      if (ocs != null)
      {
        objectClasses.addAll(ocs);
      }
    }
    Icon newIcon;
    if (node instanceof SuffixNode)
    {
      newIcon = iconPool.getSuffixIcon();
    }
    else
    {
      newIcon = iconPool.getIcon(objectClasses, modifiers);
    }
    int aciCount = getAciCount(entry);
    Icon newIcon = getNewIcon(node, entry);
    // Construct the icon text according the dn, the aci count...
    StringBuilder sb2 = new StringBuilder();
    if (aciCount >= 1) {
      sb2.append(String.valueOf(aciCount));
      if (aciCount == 1) {
        sb2.append(" aci");
      }
      else {
        sb2.append(" acis");
      sb2.append(aciCount);
      sb2.append(" aci");
      if (aciCount != 1) {
        sb2.append("s");
      }
    }
@@ -1822,8 +1591,7 @@
      }
    } else {
      boolean useRdn = true;
      if (!displayAttribute.equals(RDN_ATTRIBUTE) &&
          (entry != null)) {
      if (!RDN_ATTRIBUTE.equals(displayAttribute) && entry != null) {
        String value = ConnectionUtils.getFirstValue(entry,displayAttribute);
        if (value != null) {
          if (showAttributeName) {
@@ -1833,9 +1601,10 @@
          useRdn = false;
        }
      }
      if (useRdn) {
        String rdn;
        if (followReferrals && (node.getRemoteUrl() != null)) {
        if (followReferrals && node.getRemoteUrl() != null) {
          if (showAttributeName) {
            rdn = node.getRemoteRDNWithAttributeName();
          } else {
@@ -1866,21 +1635,66 @@
    }
    // Determine if the rendering needs to be updated
    boolean changed = (
        (node.getIcon() != newIcon) ||
        (node.getDisplayName() != newDisplayName) ||
        (node.getFontStyle() != newStyle)
    );
    boolean changed =
        node.getIcon() != newIcon
        || node.getDisplayName() != newDisplayName
        || node.getFontStyle() != newStyle;
    if (changed) {
      node.setIcon(newIcon);
      node.setDisplayName(newDisplayName);
      node.setFontStyle(newStyle);
    }
    return changed;
  }
  private int getAciCount(SearchResult entry) throws NamingException
  {
    if ((displayFlags & DISPLAY_ACI_COUNT) != 0 && entry != null) {
      Set<String> aciValues = ConnectionUtils.getValues(entry, "aci");
      if (aciValues != null) {
        return aciValues.size();
      }
    }
    return 0;
  }
  private Icon getNewIcon(BasicNode node, SearchResult entry)
      throws NamingException
  {
    // Select the icon according the objectClass,...
    int modifiers = 0;
    if (node.isLeaf() && !node.hasSubOrdinates()) {
      modifiers |= IconPool.MODIFIER_LEAF;
    }
    if (node.getReferral() != null) {
      modifiers |= IconPool.MODIFIER_REFERRAL;
    }
    if (node.getError() != null) {
      final Exception ex = node.getError().getException();
      if (ex != null)
      {
        LOG.log(Level.SEVERE, "node has error: " + ex, ex);
      }
      modifiers |= IconPool.MODIFIER_ERROR;
    }
    SortedSet<String> objectClasses = new TreeSet<String>();
    if (entry != null) {
      Set<String> ocs = ConnectionUtils.getValues(entry, "objectClass");
      if (ocs != null)
      {
        objectClasses.addAll(ocs);
      }
    }
    if (node instanceof SuffixNode)
    {
      return iconPool.getSuffixIcon();
    }
    return iconPool.getIcon(objectClasses, modifiers);
  }
  /**
   * Find a child node matching a given DN.
@@ -1895,14 +1709,13 @@
  public int findChildNode(BasicNode parent, String childDn) {
    int childCount = parent.getChildCount();
    int i = 0;
    while ((i < childCount) &&
        !childDn.equals(((BasicNode)parent.getChildAt(i)).getDN())) {
    while (i < childCount
        && !childDn.equals(((BasicNode)parent.getChildAt(i)).getDN())) {
      i++;
    }
    if (i >= childCount) { // Not found
      i = -(childCount + 1);
    }
    return i;
  }
@@ -1936,10 +1749,10 @@
      newSize = newSize - 1;
    }
    if (newSize != queueTotalSize) {
      if ((queueTotalSize == 0) && (newSize >= 1)) {
      if (queueTotalSize == 0 && newSize >= 1) {
        fireEvent(BrowserEvent.Type.UPDATE_START);
      }
      else if ((queueTotalSize >= 1) && (newSize == 0)) {
      else if (queueTotalSize >= 1 && newSize == 0) {
        fireEvent(BrowserEvent.Type.UPDATE_END);
      }
      queueTotalSize = newSize;
@@ -1985,46 +1798,44 @@
   * @throws IllegalArgumentException if a node with the given dn exists but
   * is not a suffix node.
   */
  SuffixNode findSuffixNode(String suffixDn, SuffixNode suffixNode)
  throws IllegalArgumentException
  private SuffixNode findSuffixNode(String suffixDn, SuffixNode suffixNode)
      throws IllegalArgumentException
  {
    SuffixNode result;
    if (Utilities.areDnsEqual(suffixNode.getDN(), suffixDn)) {
      result = suffixNode;
    }
    else {
      int childCount = suffixNode.getChildCount();
      if (childCount == 0) {
        result = null;
      }
      else {
        BasicNode child;
        int i = 0;
        boolean found = false;
        do {
          child = (BasicNode)suffixNode.getChildAt(i) ;
          if (Utilities.areDnsEqual(child.getDN(), suffixDn)) {
            found = true;
          }
          i++;
        }
        while ((i < childCount) && !found);
        if (!found) {
          result = null;
        }
        else if (child instanceof SuffixNode) {
          result = (SuffixNode)child;
        }
        else {
          // A node matches suffixDn however it's not a suffix node.
          // There's a bug in the caller.
          throw new IllegalArgumentException(suffixDn +" is not a suffix node");
        }
      }
      return suffixNode;
    }
    return result;
    int childCount = suffixNode.getChildCount();
    if (childCount == 0)
    {
      return null;
    }
    BasicNode child;
    int i = 0;
    boolean found = false;
    do
    {
      child = (BasicNode) suffixNode.getChildAt(i);
      if (Utilities.areDnsEqual(child.getDN(), suffixDn))
      {
        found = true;
      }
      i++;
    }
    while (i < childCount && !found);
    if (!found)
    {
      return null;
    }
    if (child instanceof SuffixNode)
    {
      return (SuffixNode) child;
    }
    // A node matches suffixDn however it's not a suffix node.
    // There's a bug in the caller.
    throw new IllegalArgumentException(suffixDn + " is not a suffix node");
  }
@@ -2036,15 +1847,7 @@
   * NameNotFoundException.
   */
  private boolean isNameNotFoundException(Object x) {
    boolean result;
    if ((x != null) && (x instanceof NameNotFoundException))
    {
      result = true;
    }
    else {
      result = false;
    }
    return result;
    return x instanceof NameNotFoundException;
  }
@@ -2054,28 +1857,12 @@
   * If numsubordinates is not present, returns 0.
   * @param entry the entry to analyze.
   * @throws NamingException if an error occurs.
   * @return the value of the numsubordinate attribute.  0 if the attribute
   * @return the value of the numsubordinates attribute.  0 if the attribute
   * could not be found.
   */
  public static int getNumSubOrdinates(SearchResult entry)
  throws NamingException
  private static int getNumSubOrdinates(SearchResult entry) throws NamingException
  {
    int result;
    String v = ConnectionUtils.getFirstValue(entry, "numsubordinates");
    if (v == null) {
      result = 0;
    }
    else {
      try {
        result = Integer.parseInt(v);
      }
      catch(NumberFormatException x) {
        result = 0;
      }
    }
    return result;
    return toInt(ConnectionUtils.getFirstValue(entry, "numsubordinates"));
  }
  /**
@@ -2090,49 +1877,46 @@
  public static boolean getHasSubOrdinates(SearchResult entry)
  throws NamingException
  {
    boolean result;
    String v = ConnectionUtils.getFirstValue(entry, "hassubordinates");
    if (v == null) {
      result = getNumSubOrdinates(entry) > 0;
    if (v != null) {
      return "true".equalsIgnoreCase(v);
    }
    else {
      result = "true".equalsIgnoreCase(v);
    }
    return result;
    return getNumSubOrdinates(entry) > 0;
  }
  /**
   * Get the value of the numsubordinates attribute.
   * If numsubordinates is not present, returns 0.
   * @param entry the entry to analyze.
   * @return the value of the numsubordinate attribute.  0 if the attribute
   * @return the value of the numsubordinates attribute.  0 if the attribute
   * could not be found.
   */
  public static int getNumSubOrdinates(CustomSearchResult entry)
  private static int getNumSubOrdinates(CustomSearchResult entry)
  {
    int result;
    List<Object> vs = entry.getAttributeValues("numsubordinates");
    String v = null;
    if (vs != null && !vs.isEmpty())
    {
      v = vs.get(0).toString();
    }
    if (v == null) {
      result = 0;
    }
    else {
      try {
        result = Integer.parseInt(v);
      }
      catch(NumberFormatException x) {
        result = 0;
      }
    }
    return toInt(v);
  }
    return result;
  private static int toInt(String v)
  {
    if (v == null)
    {
      return 0;
    }
    try
    {
      return Integer.parseInt(v);
    }
    catch (NumberFormatException x)
    {
      return 0;
    }
  }
  /**
@@ -2145,22 +1929,17 @@
   */
  public static boolean getHasSubOrdinates(CustomSearchResult entry)
  {
    boolean result;
    List<Object> vs = entry.getAttributeValues("hassubordinates");
    String v = null;
    if (vs != null && !vs.isEmpty())
    {
      v = vs.get(0).toString();
    }
    if (v == null) {
      result = getNumSubOrdinates(entry) > 0;
    if (v != null)
    {
      return "true".equalsIgnoreCase(v);
    }
    else {
      result = "true".equalsIgnoreCase(v);
    }
    return result;
    return getNumSubOrdinates(entry) > 0;
  }
@@ -2180,7 +1959,7 @@
    {
      for (String value : values)
      {
        boolean isReferral = value.equalsIgnoreCase("referral");
        boolean isReferral = "referral".equalsIgnoreCase(value);
        if (isReferral)
        {
          Set<String> refValues = ConnectionUtils.getValues(entry, "ref");
@@ -2231,7 +2010,7 @@
   * @param v the Collection of Integer objects.
   * @return an array of int from a Collection of Integer objects.
   */
  static int[] intArrayFromCollection(Collection<Integer> v) {
  private static int[] intArrayFromCollection(Collection<Integer> v) {
    int[] result = new int[v.size()];
    int i = 0;
    for (Integer value : v)
@@ -2242,29 +2021,6 @@
    return result;
  }
  /**
   * Returns an array of SearchResult from a Collection of SearchResult objects.
   * @param v the Collection of SearchResult objects.
   * @return an array of SearchResult from a Collection of SearchResult objects.
   */
  static SearchResult[] entryArrayFromCollection(Collection<SearchResult> v) {
    SearchResult[] result = new SearchResult[v.size()];
    v.toArray(result);
    return result;
  }
  /**
   * Returns an array of BasicNode from a Collection of BasicNode objects.
   * @param v the Collection of BasicNode objects.
   * @return an array of BasicNode from a Collection of BasicNode objects.
   */
  static BasicNode[] nodeArrayFromCollection(Collection<BasicNode> v) {
    BasicNode[] result = new BasicNode[v.size()];
    v.toArray(result);
    return result;
  }
  /**
   * For debugging purpose: allows to switch easily
@@ -2273,8 +2029,7 @@
   * @param r the runnable to be invoked.
   * @throws InterruptedException if there is an error invoking SwingUtilities.
   */
  static void swingInvoke(Runnable r)
  throws InterruptedException {
  private static void swingInvoke(Runnable r) throws InterruptedException {
    try {
      SwingUtilities.invokeAndWait(r);
    }
@@ -2289,23 +2044,23 @@
  /**
   * The default implementaion of the BrowserNodeInfo interface.
   * The default implementation of the BrowserNodeInfo interface.
   */
  class BrowserNodeInfoImpl implements BrowserNodeInfo
  private class BrowserNodeInfoImpl implements BrowserNodeInfo
  {
    BasicNode node;
    LDAPURL url;
    boolean isRemote;
    boolean isSuffix;
    boolean isRootNode;
    String[] referral;
    int numSubOrdinates;
    boolean hasSubOrdinates;
    int errorType;
    Exception errorException;
    Object errorArg;
    String[] objectClassValues;
    String toString;
    private BasicNode node;
    private LDAPURL url;
    private boolean isRemote;
    private boolean isSuffix;
    private boolean isRootNode;
    private String[] referral;
    private int numSubOrdinates;
    private boolean hasSubOrdinates;
    private int errorType;
    private Exception errorException;
    private Object errorArg;
    private String[] objectClassValues;
    private String toString;
    /**
     * The constructor of this object.
@@ -2353,6 +2108,7 @@
     * Returns the node associated with this object.
     * @return  the node associated with this object.
     */
    @Override
    public BasicNode getNode() {
      return node;
    }
@@ -2361,6 +2117,7 @@
     * Returns the LDAP URL associated with this object.
     * @return the LDAP URL associated with this object.
     */
    @Override
    public LDAPURL getURL() {
      return url;
    }
@@ -2370,6 +2127,7 @@
     * @return <CODE>true</CODE> if this is a root node and <CODE>false</CODE>
     * otherwise.
     */
    @Override
    public boolean isRootNode() {
      return isRootNode;
    }
@@ -2379,6 +2137,7 @@
     * @return <CODE>true</CODE> if this is a suffix node and <CODE>false</CODE>
     * otherwise.
     */
    @Override
    public boolean isSuffix() {
      return isSuffix;
    }
@@ -2388,6 +2147,7 @@
     * @return <CODE>true</CODE> if this is a remote node and <CODE>false</CODE>
     * otherwise.
     */
    @Override
    public boolean isRemote() {
      return isRemote;
    }
@@ -2396,6 +2156,7 @@
     * Returns the list of referral associated with this node.
     * @return the list of referral associated with this node.
     */
    @Override
    public String[] getReferral() {
      return referral;
    }
@@ -2406,6 +2167,7 @@
     * @return the number of subordinates of the entry associated with this
     * node.
     */
    @Override
    public int getNumSubOrdinates() {
      return numSubOrdinates;
    }
@@ -2415,6 +2177,7 @@
     * @return {@code true} if the entry has subordinates and {@code false}
     * otherwise.
     */
    @Override
    public boolean hasSubOrdinates() {
      return hasSubOrdinates;
    }
@@ -2425,6 +2188,7 @@
     * @return the error type associated we got when refreshing the node.
     * <CODE>null</CODE> if no error was found.
     */
    @Override
    public int getErrorType() {
      return errorType;
    }
@@ -2435,6 +2199,7 @@
     * @return the exception associated we got when refreshing the node.
     * <CODE>null</CODE> if no exception was found.
     */
    @Override
    public Exception getErrorException() {
      return errorException;
    }
@@ -2445,6 +2210,7 @@
     * @return the error argument associated we got when refreshing the node.
     * <CODE>null</CODE> if no error argument was found.
     */
    @Override
    public Object getErrorArg() {
      return errorArg;
    }
@@ -2453,6 +2219,7 @@
     * Return the tree path associated with the node in the tree.
     * @return the tree path associated with the node in the tree.
     */
    @Override
    public TreePath getTreePath() {
      return new TreePath(treeModel.getPathToRoot(node));
    }
@@ -2461,6 +2228,7 @@
     * Returns the object class values of the entry associated with the node.
     * @return the object class values of the entry associated with the node.
     */
    @Override
    public String[] getObjectClassValues() {
      return objectClassValues;
    }
@@ -2469,6 +2237,7 @@
     * Returns a String representation of the object.
     * @return a String representation of the object.
     */
    @Override
    public String toString() {
      return toString;
    }
@@ -2479,12 +2248,12 @@
     * @return <CODE>true</CODE> if the node info represents the same node as
     * this and <CODE>false</CODE> otherwise.
     */
    @Override
    public boolean representsSameNode(BrowserNodeInfo node) {
      boolean representsSameNode = false;
      if (node != null) {
        representsSameNode = node.getNode() == node;
        return node.getNode() == node;
      }
      return representsSameNode;
      return false;
    }
  }
opends/src/guitools/org/opends/guitools/controlpanel/browser/IconPool.java
@@ -22,20 +22,10 @@
 *
 *
 *      Copyright 2008-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2013 ForgeRock AS.
 *      Portions Copyright 2013-2014 ForgeRock AS.
 */
package org.opends.guitools.controlpanel.browser;
import static org.opends.messages.AdminToolMessages.*;
import java.awt.Canvas;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.util.HashMap;
import java.util.Set;
import java.util.SortedSet;
@@ -46,6 +36,8 @@
import org.opends.quicksetup.ui.UIFactory;
import org.opends.server.util.ServerConstants;
import static org.opends.messages.AdminToolMessages.*;
/**
 * This class is used as a cache containing the icons that are used by the
 * BrowserController to update the nodes.  It keeps some icons associated with
@@ -66,10 +58,11 @@
   */
  public static final int MODIFIER_ERROR    = 0x04;
  private HashMap<String, ImageIcon> iconTable =
  private final HashMap<String, ImageIcon> iconTable =
    new HashMap<String, ImageIcon>();
  private HashMap<String, String> pathTable = new HashMap<String, String>();
  private HashMap<String, String> descriptionTable =
  private final HashMap<String, String> pathTable =
      new HashMap<String, String>();
  private final HashMap<String, String> descriptionTable =
    new HashMap<String, String>();
  private ImageIcon defaultLeafIcon;
  private ImageIcon suffixIcon;
@@ -117,12 +110,9 @@
    "passwordpolicy", INFO_PASSWORD_POLICY_ICON_DESCRIPTION.get().toString()
  };
  private String GENERIC_OBJECT_DESCRIPTION = "Generic entry";
  private final String GENERIC_OBJECT_DESCRIPTION = "Generic entry";
  /**
   * The default constructor.
   *
   */
  /** The default constructor. */
  public IconPool() {
    // Recopy ICON_PATH in pathTable for fast access
    for (int i = 0; i < ICON_PATH.length; i = i+2) {
@@ -144,15 +134,12 @@
   * modifiers.
   */
  public ImageIcon getIcon(SortedSet<String> objectClasses, int modifiers) {
    ImageIcon result;
    String key = makeKey(objectClasses, modifiers);
    result = iconTable.get(key);
    ImageIcon result = iconTable.get(key);
    if (result == null) {
      result = makeIcon(objectClasses, modifiers);
      iconTable.put(key, result);
    }
    return result;
  }
@@ -270,7 +257,7 @@
    ImageIcon result;
    // Find the icon associated to the object class
    if ((objectClasses == null) || (objectClasses.size() == 0)) {
    if (objectClasses == null || objectClasses.size() == 0) {
      result = getDefaultContainerIcon();
    }
    else {
@@ -328,87 +315,8 @@
    if(ocValues != null) {
      result.append(Utilities.getStringFromCollection(ocValues, ""));
    }
    result.append(String.valueOf(modifiers));
    result.append(modifiers);
    return result.toString();
  }
    /**
     * Returns a RemoteImage corresponding to the superposition of the icon
     * Image and the mask Image.
     *
     * @param icon the RemoteImage that we want to bar.
     * @param mask the ImageIcond to be used as mask.
     * @return a RemoteImage corresponding to the superposition of the icon
     * Image and the mask Image.
     */
  public static ImageIcon maskedIcon(ImageIcon icon, ImageIcon mask) {
    ImageIcon fReturn;
    int TRANSPARENT = 16711165;  // The value of a transparent pixel
    int h = icon.getIconHeight();
    int w = icon.getIconWidth();
    if (mask.getImageLoadStatus() != MediaTracker.COMPLETE) {
      return null;
    }
    Image maskImage = mask.getImage();
    Image scaledMaskImage = maskImage.getScaledInstance(w, h ,
        Image.SCALE_SMOOTH);
    ImageIcon scaledMask = new ImageIcon(scaledMaskImage);
    if (scaledMask.getImageLoadStatus() != MediaTracker.COMPLETE) {
      return null;
    }
    int[] iconPixels = new int[w * h];
    try {
      PixelGrabber pg =
        new PixelGrabber(icon.getImage(), 0, 0, w, h, iconPixels, 0, w);
      pg.grabPixels();
      if ((pg.status() & ImageObserver.ABORT) !=0) {
        return null;
      }
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
    int[] filterPixels = new int[w * h];
    try {
      PixelGrabber pgf =
        new PixelGrabber(scaledMask.getImage(), 0, 0, w, h, filterPixels, 0, w);
      pgf.grabPixels();
      if ((pgf.status() & ImageObserver.ABORT) !=0) {
        fReturn = null;
        return fReturn;
      }
    } catch (Exception e) {
      e.printStackTrace();
      fReturn = null;
      return fReturn;
    }
    int[] newPixels = new int[w * h];
    for( int i = 0; i < h; i++)
      for (int j = 0; j < w; j++)
        if (filterPixels[j + i*w] != TRANSPARENT) {
          newPixels[j + i*w] = filterPixels[j + i*w];
        } else {
          newPixels[j + i*w] = iconPixels[j + i*w];
        }
    Canvas component = new Canvas();
    Image newImage = component.getToolkit().createImage(
        new MemoryImageSource(
            w, h, ColorModel.getRGBdefault(), newPixels, 0, w));
    fReturn = new ImageIcon(newImage, icon.getDescription());
    return fReturn;
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/browser/LDAPConnectionPool.java
@@ -22,12 +22,11 @@
 *
 *
 *      Copyright 2008-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2014 ForgeRock AS
 */
package org.opends.guitools.controlpanel.browser;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import javax.naming.NamingException;
@@ -42,6 +41,8 @@
import org.opends.server.types.LDAPURL;
import org.opends.server.types.SearchScope;
import static org.opends.admin.ads.util.ConnectionUtils.*;
/**
 * An LDAPConnectionPool is a pool of LDAPConnection.
 * <BR><BR>
@@ -71,11 +72,12 @@
 */
public class LDAPConnectionPool {
  HashMap<String, AuthRecord> authTable = new HashMap<String, AuthRecord>();
  HashMap<String, ConnectionRecord> connectionTable =
  private final HashMap<String, AuthRecord> authTable =
      new HashMap<String, AuthRecord>();
  private final HashMap<String, ConnectionRecord> connectionTable =
    new HashMap<String, ConnectionRecord>();
  ArrayList<ReferralAuthenticationListener> listeners;
  private ArrayList<ReferralAuthenticationListener> listeners;
  private Control[] requestControls = new Control[] {};
  private ApplicationTrustManager trustManager;
@@ -89,28 +91,20 @@
   * connection pool, <CODE>false</CODE> otherwise.
   */
  public boolean isConnectionRegistered(InitialLdapContext ctx) {
    boolean isConnectionRegistered = false;
    for (String key : connectionTable.keySet())
    {
      ConnectionRecord cr = connectionTable.get(key);
      if (cr.ctx != null) {
        isConnectionRegistered =
         ConnectionUtils.getHostName(cr.ctx).equals(
             ConnectionUtils.getHostName(ctx)) &&
        (ConnectionUtils.getPort(cr.ctx) == ConnectionUtils.getPort(ctx)) &&
        ConnectionUtils.getBindDN(cr.ctx).equals(
            ConnectionUtils.getBindDN(ctx)) &&
        ConnectionUtils.getBindPassword(cr.ctx).equals(
            ConnectionUtils.getBindPassword(ctx)) &&
        (ConnectionUtils.isSSL(cr.ctx) == ConnectionUtils.isSSL(ctx)) &&
        (ConnectionUtils.isStartTLS(cr.ctx) == ConnectionUtils.isStartTLS(ctx));
      }
      if (isConnectionRegistered)
      {
        break;
      if (cr.ctx != null
          && getHostName(cr.ctx).equals(getHostName(ctx))
          && getPort(cr.ctx) == getPort(ctx)
          && getBindDN(cr.ctx).equals(getBindDN(ctx))
          && getBindPassword(cr.ctx).equals(getBindPassword(ctx))
          && isSSL(cr.ctx) == isSSL(ctx)
          && isStartTLS(cr.ctx) == isStartTLS(ctx)) {
        return true;
      }
    }
    return isConnectionRegistered;
    return false;
  }
  /**
@@ -119,12 +113,7 @@
   */
  public void registerConnection(InitialLdapContext ctx) {
    registerAuth(ctx);
    LDAPURL url = makeLDAPUrl(
                  ConnectionUtils.getHostName(ctx),
                  ConnectionUtils.getPort(ctx),
                  "",
                  ConnectionUtils.isSSL(ctx)
                  );
    LDAPURL url = makeLDAPUrl(ctx);
    String key = makeKeyFromLDAPUrl(url);
    ConnectionRecord cr = new ConnectionRecord();
    cr.ctx = ctx;
@@ -141,11 +130,7 @@
  public void unregisterConnection(InitialLdapContext ctx)
  throws NamingException
  {
    LDAPURL url = makeLDAPUrl(
        ConnectionUtils.getHostName(ctx),
        ConnectionUtils.getPort(ctx),
        "",
        ConnectionUtils.isSSL(ctx));
    LDAPURL url = makeLDAPUrl(ctx);
    unRegisterAuth(url);
    String key = makeKeyFromLDAPUrl(url);
    connectionTable.remove(key);
@@ -164,17 +149,6 @@
  }
  /**
   * Removes a referral authentication listener.
   * @param listener the referral authentication listener.
   */
  public void removeReferralAuthenticationListener(
      ReferralAuthenticationListener listener) {
    if (listeners != null) {
      listeners.remove(listener);
    }
  }
  /**
   * Returns an LDAPConnection for accessing the specified url.
   * If no connection are available for the protocol/host/port
   * of the URL, getConnection() makes a new one and call connect().
@@ -287,35 +261,17 @@
    if (targetRecord == null) { // ldc is not in _connectionTable -> bug
      throw new IllegalArgumentException("Invalid LDAP connection");
    }
    else {
      synchronized(targetRecord) {
        targetRecord.counter--;
        if ((targetRecord.counter == 0) && targetRecord.disconnectAfterUse) {
          disconnectAndRemove(targetRecord);
        }
      }
    }
  }
  /**
   * Disconnect the connections which are not being used.
   * Connections being used will be disconnected as soon
   * as they are released.
   */
  public synchronized void flush() {
    for (ConnectionRecord cr : connectionTable.values())
    synchronized (targetRecord)
    {
      if (cr.counter <= 0) {
        disconnectAndRemove(cr);
      }
      else {
        cr.disconnectAfterUse = true;
      targetRecord.counter--;
      if (targetRecord.counter == 0 && targetRecord.disconnectAfterUse)
      {
        disconnectAndRemove(targetRecord);
      }
    }
  }
  /**
   * Register authentication data.
   * If authentication data are already available for the protocol/host/port
@@ -331,14 +287,11 @@
   * provided authentication (for testing purposes).
   * @throws NamingException if an error occurs connecting.
   */
  public void registerAuth(LDAPURL ldapUrl, String dn, String pw,
      boolean connect)
  throws NamingException {
  private void registerAuth(LDAPURL ldapUrl, String dn, String pw,
      boolean connect) throws NamingException {
    String key = makeKeyFromLDAPUrl(ldapUrl);
    AuthRecord ar;
    ar = new AuthRecord();
    ar.ldapUrl  = ldapUrl;
    final AuthRecord ar = new AuthRecord();
    ar.dn       = dn;
    ar.password = pw;
@@ -371,15 +324,10 @@
   * @param ctx the connection that we retrieve the authentication information
   * from.
   */
  public void registerAuth(InitialLdapContext ctx) {
    LDAPURL url = makeLDAPUrl(
      ConnectionUtils.getHostName(ctx),
      ConnectionUtils.getPort(ctx),
      "",
      ConnectionUtils.isSSL(ctx));
  private void registerAuth(InitialLdapContext ctx) {
    LDAPURL url = makeLDAPUrl(ctx);
    try {
      registerAuth(url, ConnectionUtils.getBindDN(ctx),
          ConnectionUtils.getBindPassword(ctx), false);
      registerAuth(url, getBindDN(ctx), getBindPassword(ctx), false);
    }
    catch (NamingException x) {
      throw new RuntimeException("Bug");
@@ -395,7 +343,7 @@
   * unregistered.
   * @throws NamingException if the unbind fails.
   */
  public void unRegisterAuth(LDAPURL ldapUrl) throws NamingException {
  private void unRegisterAuth(LDAPURL ldapUrl) throws NamingException {
    String key = makeKeyFromLDAPUrl(ldapUrl);
    authTable.remove(key);
@@ -403,45 +351,6 @@
  }
  /**
   * Get authentication DN registered for this url.
   * @param ldapUrl the LDAP URL for which we want to get authentication DN.
   * @return the bind DN of the authentication.
   */
  public synchronized String getAuthDN(LDAPURL ldapUrl) {
    String result;
    String key = makeKeyFromLDAPUrl(ldapUrl);
    AuthRecord ar = authTable.get(key);
    if (ar == null) {
      result = null;
    }
    else {
      result = ar.dn;
    }
    return result;
  }
  /**
   * Get authentication password registered for this url.
   * @param ldapUrl the LDAP URL for which we want to get authentication
   * password.
   * @return the password of the authentication.
   */
  public synchronized String getAuthPassword(LDAPURL ldapUrl) {
    String result;
    String key = makeKeyFromLDAPUrl(ldapUrl);
    AuthRecord ar = authTable.get(key);
    if (ar == null) {
      result = null;
    }
    else {
      result = ar.password;
    }
    return result;
  }
  /**
   * Disconnect the connection associated to a record
   * and remove the record from connectionTable.
   * @param cr the ConnectionRecord to remove.
@@ -490,8 +399,7 @@
   */
  private static String makeKeyFromRecord(ConnectionRecord rec) {
    String protocol = ConnectionUtils.isSSL(rec.ctx) ? "LDAPS" : "LDAP";
    return protocol + ":" + ConnectionUtils.getHostName(rec.ctx) + ":" +
    ConnectionUtils.getPort(rec.ctx);
    return protocol + ":" + getHostName(rec.ctx) + ":" + getPort(rec.ctx);
  }
  /**
@@ -505,24 +413,18 @@
  private InitialLdapContext createLDAPConnection(LDAPURL ldapUrl,
      AuthRecord ar) throws NamingException
  {
    InitialLdapContext ctx;
    // Take the base DN out of the URL and only keep the protocol, host and port
    ldapUrl = new LDAPURL(ldapUrl.getScheme(), ldapUrl.getHost(),
          ldapUrl.getPort(), (DN)null, null, null, null, null);
    if (isSecureLDAPUrl(ldapUrl))
    {
      ctx = ConnectionUtils.createLdapsContext(ldapUrl.toString(), ar.dn,
      return ConnectionUtils.createLdapsContext(ldapUrl.toString(), ar.dn,
          ar.password, getConnectTimeout(), null,
          getTrustManager() , getKeyManager());
          getTrustManager(), getKeyManager());
    }
    else
    {
      ctx = ConnectionUtils.createLdapContext(ldapUrl.toString(), ar.dn,
          ar.password, getConnectTimeout(), null);
    }
    return ctx;
    return ConnectionUtils.createLdapContext(ldapUrl.toString(), ar.dn,
        ar.password, getConnectTimeout(), null);
  }
  /**
@@ -579,26 +481,16 @@
   * @return <CODE>true</CODE> if the LDAP URL is secure and <CODE>false</CODE>
   * otherwise.
   */
  public static boolean isSecureLDAPUrl(LDAPURL url) {
  private static boolean isSecureLDAPUrl(LDAPURL url) {
    return !LDAPURL.DEFAULT_SCHEME.equalsIgnoreCase(url.getScheme());
  }
  /**
   * Make an url from the specified arguments.
   * @param host the host.
   * @param port the port.
   * @param dn the dn.
   * @param secure whether it is a secure URL or not.
   * @return an LDAP URL from the specified arguments.
   */
  public static LDAPURL makeLDAPUrl(String host, int port, String dn,
      boolean secure) {
  private LDAPURL makeLDAPUrl(InitialLdapContext ctx) {
    return new LDAPURL(
        secure ? "ldaps" : LDAPURL.DEFAULT_SCHEME,
            host,
            port,
            dn,
        isSSL(ctx) ? "ldaps" : LDAPURL.DEFAULT_SCHEME,
            getHostName(ctx),
            getPort(ctx),
            "",
            null, // no attributes
            SearchScope.BASE_OBJECT,
            null, // No filter
@@ -643,20 +535,12 @@
        null); // No extensions
  }
  /**
   * Returns a collection of AuthRecord.
   * @return a collection of AuthRecord.
   */
  Collection<?> getRegisteredAuthentication() {
    return authTable.values();
  }
}
/**
 * A structure representing authentication data.
 */
class AuthRecord {
  LDAPURL ldapUrl;
  String dn;
  String password;
}
opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java
@@ -27,7 +27,7 @@
package org.opends.server.replication.plugin;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -51,7 +51,7 @@
 */
class PersistentServerState
{
   private final DN baseDn;
   private final DN baseDN;
   private final int serverId;
   private final ServerState state;
@@ -64,13 +64,13 @@
   * Create a new PersistentServerState based on an already existing
   * ServerState.
   *
   * @param baseDn    The baseDN for which the ServerState is created.
   * @param baseDN    The baseDN for which the ServerState is created.
   * @param serverId  The serverId.
   * @param state     The serverState.
   */
  PersistentServerState(DN baseDn, int serverId, ServerState state)
  PersistentServerState(DN baseDN, int serverId, ServerState state)
  {
    this.baseDn = baseDn;
    this.baseDN = baseDN;
    this.serverId = serverId;
    this.state = state;
    loadState();
@@ -108,7 +108,7 @@
  {
    if (!state.isSaved())
    {
      state.setSaved(updateStateEntry() == ResultCode.SUCCESS);
      state.setSaved(updateStateEntry());
    }
  }
@@ -158,18 +158,16 @@
       * Search the database entry that is used to periodically
       * save the ServerState
       */
      LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
      attributes.add(REPLICATION_STATE);
      final InternalSearchOperation search = getRootConnection().processSearch(
          baseDn,
          SearchScope.BASE_OBJECT, DereferencePolicy.NEVER_DEREF_ALIASES,
          0, 0, false, filter, attributes);
      if (((search.getResultCode() != ResultCode.SUCCESS)) &&
          ((search.getResultCode() != ResultCode.NO_SUCH_OBJECT)))
          baseDN, SearchScope.BASE_OBJECT, DereferencePolicy.NEVER_DEREF_ALIASES,
          0, 0, false, filter, Collections.singleton(REPLICATION_STATE));
      final ResultCode resultCode = search.getResultCode();
      if (resultCode != ResultCode.SUCCESS
          && resultCode != ResultCode.NO_SUCH_OBJECT)
      {
        logError(ERR_ERROR_SEARCHING_RUV.get(
            search.getResultCode().getResultCodeName(), search.toString(),
            search.getErrorMessage(), baseDn.toString()));
            resultCode.getResultCodeName(), search.toString(),
            search.getErrorMessage(), baseDN.toString()));
        return null;
      }
      return getFirstResult(search);
@@ -193,15 +191,13 @@
    {
      SearchFilter filter = SearchFilter.createFilterFromString(
          "(&(objectclass=ds-cfg-replication-domain)"
          + "(ds-cfg-base-dn=" + baseDn + "))");
          + "(ds-cfg-base-dn=" + baseDN + "))");
      LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
      attributes.add(REPLICATION_STATE);
      final InternalSearchOperation op = getRootConnection().processSearch(
          DN.decode("cn=config"),
          SearchScope.SUBORDINATE_SUBTREE,
          DereferencePolicy.NEVER_DEREF_ALIASES,
          1, 0, false, filter, attributes);
          1, 0, false, filter, Collections.singleton(REPLICATION_STATE));
      return getFirstResult(op);
    }
    catch (DirectoryException e)
@@ -234,12 +230,10 @@
  {
    AttributeType synchronizationStateType =
      DirectoryServer.getAttributeType(REPLICATION_STATE);
    List<Attribute> attrs =
      resultEntry.getAttribute(synchronizationStateType);
    List<Attribute> attrs = resultEntry.getAttribute(synchronizationStateType);
    if (attrs != null)
    {
      Attribute attr = attrs.get(0);
      for (AttributeValue value : attr)
      for (AttributeValue value : attrs.get(0))
      {
        update(new CSN(value.toString()));
      }
@@ -250,12 +244,12 @@
   * Save the current values of this PersistentState object
   * in the appropriate entry of the database.
   *
   * @return a ResultCode indicating if the method was successful.
   * @return a boolean indicating if the method was successful.
   */
  private ResultCode updateStateEntry()
  private boolean updateStateEntry()
  {
    // Generate a modify operation on the Server State baseDN Entry.
    ResultCode result = runUpdateStateEntry(baseDn);
    ResultCode result = runUpdateStateEntry(baseDN);
    if (result == ResultCode.NO_SUCH_OBJECT)
    {
      // The base entry does not exist yet in the database or has been deleted,
@@ -263,11 +257,10 @@
      SearchResultEntry configEntry = searchConfigEntry();
      if (configEntry != null)
      {
        DN configDN = configEntry.getDN();
        result = runUpdateStateEntry(configDN);
        result = runUpdateStateEntry(configEntry.getDN());
      }
    }
    return result;
    return result == ResultCode.SUCCESS;
  }
  /**
@@ -283,14 +276,12 @@
    ArrayList<ByteString> values = state.toASN1ArrayList();
    LDAPAttribute attr = new LDAPAttribute(REPLICATION_STATE, values);
    LDAPModification mod = new LDAPModification(ModificationType.REPLACE, attr);
    ArrayList<RawModification> mods = new ArrayList<RawModification>(1);
    mods.add(mod);
    RawModification mod = new LDAPModification(ModificationType.REPLACE, attr);
    ModifyOperationBasis op = new ModifyOperationBasis(getRootConnection(),
          nextOperationID(), nextMessageID(), null,
          ByteString.valueOf(serverStateEntryDN.toString()),
          mods);
          Collections.singletonList(mod));
    op.setInternalOperation(true);
    op.setSynchronizationOperation(true);
    op.setDontSynchronize(true);
@@ -301,7 +292,7 @@
              op.getResultCode().getResultCodeName().toString(),
              op.toString(),
              op.getErrorMessage().toString(),
              baseDn.toString()));
              baseDN.toString()));
    }
    return op.getResultCode();
  }
@@ -356,7 +347,7 @@
      InternalSearchOperation op;
      try
      {
        op = LDAPReplicationDomain.searchForChangedEntries(baseDn,
        op = LDAPReplicationDomain.searchForChangedEntries(baseDN,
                serverStateMaxCSN, null);
      }
      catch (Exception  e)
@@ -368,7 +359,7 @@
      {
        // An error happened trying to search for the updates
        // Log an error
        logError(ERR_CANNOT_RECOVER_CHANGES.get(baseDn.toNormalizedString()));
        logError(ERR_CANNOT_RECOVER_CHANGES.get(baseDN.toNormalizedString()));
        return;
      }
@@ -394,7 +385,7 @@
      {
        // Update the serverState with the new maxCSN present in the database
        update(dbMaxCSN);
        logError(NOTE_SERVER_STATE_RECOVERY.get(baseDn.toNormalizedString(),
        logError(NOTE_SERVER_STATE_RECOVERY.get(baseDN.toNormalizedString(),
            dbMaxCSN.toString()));
      }
    }
@@ -411,4 +402,14 @@
  {
    return state.getCSN(serverId);
  }
  /** {@inheritDoc} */
  @Override
  public String toString()
  {
    return getClass().getSimpleName()
        + " baseDN=" + baseDN
        + " serverId=" + serverId
        + " " + REPLICATION_STATE + "=" + state;
  }
}
opends/src/server/org/opends/server/replication/server/MessageHandler.java
@@ -295,31 +295,11 @@
           *           restart as usual
           *   load this change on the delayList
           */
          DBCursor<UpdateMsg> cursor = null;
          try
          {
            // fill the lateQueue
            cursor = replicationServerDomain.getCursorFrom(serverState);
            while (cursor.next() && isLateQueueBelowThreshold())
            {
              lateQueue.add(cursor.getRecord());
            }
          }
          catch (ChangelogException e)
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          finally
          {
            close(cursor);
          }
          /*
           * If the late queue is empty then we could not find any messages in
           * the replication log so the remote server is not late anymore.
           */
          fillLateQueue();
          if (lateQueue.isEmpty())
          {
            // we could not find any messages in the changelog
            // so the remote server is not late anymore.
            synchronized (msgQueue)
            {
              // Ensure we are below threshold so this server will follow the
@@ -333,8 +313,8 @@
          else
          {
            /*
             * if the first change in the lateQueue is also on the regular
             * queue, we can resume the processing from the regular queue
             * if the first change in the lateQueue is also on the regular queue,
             * we can resume the processing from the regular queue
             * -> set following to true and empty the lateQueue.
             */
            UpdateMsg msg = lateQueue.first();
@@ -356,7 +336,7 @@
        {
          // get the next change from the lateQueue
          UpdateMsg msg;
          synchronized (msgQueue)
          synchronized (msgQueue) // TODO JNR why synchronize(msgQueue) here?
          {
            msg = lateQueue.removeFirst();
          }
@@ -409,6 +389,27 @@
    return null;
  }
  private void fillLateQueue()
  {
    DBCursor<UpdateMsg> cursor = null;
    try
    {
      cursor = replicationServerDomain.getCursorFrom(serverState);
      while (cursor.next() && isLateQueueBelowThreshold())
      {
        lateQueue.add(cursor.getRecord());
      }
    }
    catch (ChangelogException e)
    {
      TRACER.debugCaught(DebugLogLevel.ERROR, e);
    }
    finally
    {
      close(cursor);
    }
  }
  private boolean isLateQueueBelowThreshold()
  {
    return lateQueue.count() < 100 && lateQueue.bytesCount() < 50000;
@@ -428,16 +429,14 @@
      {
        if (!msgQueue.isEmpty())
        {
          UpdateMsg msg = msgQueue.first();
          result = msg.getCSN();
          result = msgQueue.first().getCSN();
        }
      }
      else
      {
        if (!lateQueue.isEmpty())
        {
          UpdateMsg msg = lateQueue.first();
          result = msg.getCSN();
          result = lateQueue.first().getCSN();
        }
        else
        {
opends/src/server/org/opends/server/replication/server/MsgQueue.java
@@ -22,14 +22,12 @@
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions copyright 2012-2013 ForgeRock AS.
 *      Portions copyright 2012-2014 ForgeRock AS.
 */
package org.opends.server.replication.server;
import java.util.NavigableMap;
import java.util.TreeMap;
import org.opends.messages.Message;
import org.opends.server.replication.common.CSN;
import org.opends.server.replication.protocol.UpdateMsg;
@@ -39,10 +37,18 @@
/**
 * This class is used to build ordered lists of UpdateMsg.
 * The order is defined by the order of the CSN of the UpdateMsg.
 * @ThreadSafe
 */
public class MsgQueue
{
  private NavigableMap<CSN, UpdateMsg> map = new TreeMap<CSN, UpdateMsg>();
  private TreeMap<CSN, UpdateMsg> map = new TreeMap<CSN, UpdateMsg>();
  /**
   * FIXME JNR to be investigated:
   * I strongly suspect that we could replace this field
   * by using the synchronized keyword on each method.
   * However, MessageHandler is weirdly synchronizing on msgQueue field
   * even though it is touching the lateQueue field (?!?).
   */
  private final Object lock = new Object();
  /** The total number of bytes for all the message in the queue. */
@@ -110,7 +116,7 @@
  {
    synchronized (lock)
    {
      UpdateMsg msgSameCSN = map.put(update.getCSN(), update);
      final UpdateMsg msgSameCSN = map.put(update.getCSN(), update);
      if (msgSameCSN != null)
      {
        try
@@ -121,14 +127,13 @@
          {
            // Adding 2 msgs with the same CSN is ok only when
            // the 2 msgs are the same
            bytesCount += (update.size() - msgSameCSN.size());
            Message errMsg = ERR_RSQUEUE_DIFFERENT_MSGS_WITH_SAME_CN.get(
            bytesCount += update.size() - msgSameCSN.size();
            logError(ERR_RSQUEUE_DIFFERENT_MSGS_WITH_SAME_CN.get(
                msgSameCSN.getCSN().toString(),
                msgSameCSN.toString(), update.toString());
            logError(errMsg);
                msgSameCSN.toString(), update.toString()));
          }
        }
        catch(Exception e)
        catch (Exception e)
        {}
      }
      else
@@ -148,14 +153,15 @@
  {
    synchronized (lock)
    {
      UpdateMsg update = map.get(map.firstKey());
      // FIXME JNR replace next 2 lines with just that one:
      // final UpdateMsg update = map.pollFirstEntry().getValue();
      final UpdateMsg update = map.get(map.firstKey());
      map.remove(update.getCSN());
      bytesCount -= update.size();
      if ((map.size() == 0) && (bytesCount != 0))
      if (map.isEmpty() && bytesCount != 0)
      {
        // should never happen
        Message msg = ERR_BYTE_COUNT.get(Integer.toString(bytesCount));
        logError(msg);
        logError(ERR_BYTE_COUNT.get(Integer.toString(bytesCount)));
        bytesCount = 0;
      }
      return update;
@@ -197,18 +203,33 @@
   * message. If the passed in message is not contained in the current queue,
   * then all messages will be removed from it.
   *
   * @param msg
   * @param finalMsg
   *          the final message to reach when consuming messages from this queue
   */
  public void consumeUpTo(UpdateMsg msg)
  public void consumeUpTo(UpdateMsg finalMsg)
  {
    UpdateMsg msg1;
    // FIXME this code could be more efficient if the msgQueue could call the
    // following code (to be tested):
    // if (!map.containsKey(finalMsg.getCSN())) {
    // map.clear();
    // } else {
    // map.headMap(finalMsg.getCSN(), true).clear();
    // }
    final CSN finalCSN = finalMsg.getCSN();
    UpdateMsg msg;
    do
    {
      // FIXME this code could be more efficient if the msgQueue could call the
      // following code (to be tested):
      // map.headMap(msg.getCSN(), true).clear()
      msg1 = removeFirst();
    } while (!msg.getCSN().equals(msg1.getCSN()));
      msg = removeFirst();
    }
    while (!finalCSN.equals(msg.getCSN()));
  }
  /** {@inheritDoc} */
  @Override
  public String toString()
  {
    return getClass().getSimpleName() + " bytesCount=" + bytesCount + " queue="
        + map.values();
  }
}
opends/src/server/org/opends/server/replication/server/changelog/je/JEReplicaDBCursor.java
@@ -30,7 +30,7 @@
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.changelog.api.ChangelogException;
import org.opends.server.replication.server.changelog.api.DBCursor;
import org.opends.server.replication.server.changelog.je.ReplicationDB.*;
import org.opends.server.replication.server.changelog.je.ReplicationDB.ReplServerDBCursor;
/**
 * Berkeley DB JE implementation of {@link DBCursor}.
@@ -89,11 +89,7 @@
    final ReplServerDBCursor localCursor = cursor;
    currentChange = localCursor != null ? localCursor.next() : null;
    if (currentChange != null)
    {
      lastNonNullCurrentCSN = currentChange.getCSN();
    }
    else
    if (currentChange == null)
    {
      synchronized (this)
      {
@@ -105,13 +101,14 @@
        // and fixing such issue with unit tests.
        cursor = db.openReadCursor(lastNonNullCurrentCSN);
        currentChange = cursor.next();
        if (currentChange != null)
        {
          lastNonNullCurrentCSN = currentChange.getCSN();
        }
      }
    }
    return currentChange != null;
    if (currentChange != null)
    {
      lastNonNullCurrentCSN = currentChange.getCSN();
      return true;
    }
    return false;
  }
  /** {@inheritDoc} */
opends/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
@@ -22,33 +22,33 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2013 ForgeRock AS.
 *      Portions copyright 2013-2014 ForgeRock AS.
 */
package org.opends.server.monitors;
import java.util.ArrayList;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.annotations.AfterClass;
import java.util.Iterator;
import java.util.Set;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.types.*;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.opends.server.protocols.internal.InternalClientConnection.*;
import static org.opends.server.types.SearchFilter.*;
import static org.opends.server.types.SearchScope.*;
import static org.testng.Assert.*;
/**
 * Interacts with the Directory Server monitor providers by retrieving the
 * monitor entries with internal searches.
 */
@SuppressWarnings("javadoc")
public class InternalSearchMonitorTestCase
       extends MonitorTestCase
{
@@ -56,20 +56,15 @@
  /**
   * Ensures that the Directory Server is started.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @BeforeClass()
  public void startServer()
         throws Exception
  @BeforeClass
  public void startServer() throws Exception
  {
    TestCaseUtils.startServer();
    DirectoryServer.registerMonitorProvider(testMonitorProvider);
  }
  @AfterClass()
  @AfterClass
  public void deregisterTestMonitor()
  {
    DirectoryServer.deregisterMonitorProvider(testMonitorProvider);
@@ -77,19 +72,13 @@
  /**
   * Uses an internal subtree search to retrieve the monitor entries.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test
  public void testWithSubtreeMonitorSearch()
         throws Exception
  public void testWithSubtreeMonitorSearch() throws Exception
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(DN.decode("cn=monitor"), SearchScope.WHOLE_SUBTREE,
              SearchFilter.createFilterFromString("(objectClass=*)"));
    assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
    InternalSearchOperation op = getRootConnection().processSearch(
        "cn=monitor", WHOLE_SUBTREE, "(objectClass=*)");
    assertEquals(op.getResultCode(), ResultCode.SUCCESS);
  }
@@ -102,18 +91,14 @@
  @DataProvider(name = "monitorNames")
  public Object[][] getMonitorNames()
  {
    ArrayList<String> monitorNames = new ArrayList<String>();
    for (String name : DirectoryServer.getMonitorProviders().keySet())
    {
      monitorNames.add(name);
    }
    Set<String> monitorNames = DirectoryServer.getMonitorProviders().keySet();
    Iterator<String> it = monitorNames.iterator();
    Object[][] nameArray = new Object[monitorNames.size()][1];
    for (int i=0; i < nameArray.length; i++)
    {
      nameArray[i] = new Object[] { monitorNames.get(i) };
      nameArray[i] = new Object[] { it.next() };
    }
    return nameArray;
  }
@@ -123,52 +108,36 @@
   * Uses a set of internal base-level searches to retrieve the monitor entries.
   *
   * @param  monitorName  The name of the monitor entry to retrieve.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "monitorNames")
  public void testWithBaseObjectMonitorSearch(String monitorName)
         throws Exception
  public void testWithBaseObjectMonitorSearch(String monitorName) throws Exception
  {
    // could be more than one level
    DN monitorDN = DN.decode("cn="+monitorName+",cn=monitor");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(monitorDN,
              SearchScope.BASE_OBJECT,
              SearchFilter.createFilterFromString("(objectClass=*)"));
    assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
    final String monitorDN = "cn="+monitorName+",cn=monitor";
    InternalSearchOperation op = getRootConnection().processSearch(
        monitorDN, BASE_OBJECT, "(objectClass=*)");
    assertEquals(op.getResultCode(), ResultCode.SUCCESS);
  }
  /**
   * Uses an internal subtree search to retrieve the monitor entries, then
   * verifies that the resulting entry DNs can be used to get the same
   * entries with a base object search.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test
  public void testWithSubtreeAndBaseMonitorSearch()
         throws Exception
  public void testWithSubtreeAndBaseMonitorSearch() throws Exception
  {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(DN.decode("cn=monitor"), SearchScope.WHOLE_SUBTREE,
              SearchFilter.createFilterFromString("(objectClass=*)"));
    final InternalClientConnection conn = getRootConnection();
    InternalSearchOperation searchOperation = conn.processSearch(
        "cn=monitor", WHOLE_SUBTREE, "(objectClass=*)");
    assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
    for (SearchResultEntry sre : searchOperation.getSearchEntries())
    {
      SearchFilter filter =
           SearchFilter.createFilterFromString("(objectClass=*)");
      searchOperation =
           conn.processSearch(sre.getDN(), SearchScope.BASE_OBJECT, filter);
      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
      final InternalSearchOperation op = conn.processSearch(
          sre.getDN(), BASE_OBJECT, createFilterFromString("(objectClass=*)"));
      assertEquals(op.getResultCode(), ResultCode.SUCCESS);
    }
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ExternalChangeLogTest.java
@@ -28,7 +28,6 @@
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.net.Socket;
import java.util.*;
@@ -159,17 +158,7 @@
    debugInfo("configure", "ReplicationServer created"+replicationServer);
  }
  /**
   * Launcher.
   */
  @Test(enabled=true)
  public void PreTest() throws Exception
  {
    // No RSDomain created yet => RS only case => ECL is not a supported
    ECLIsNotASupportedSuffix();
  }
  @Test(enabled=true, dependsOnMethods = { "PreTest"})
  @Test(enabled = true, dependsOnMethods = { "TestECLIsNotASupportedSuffix" })
  public void PrimaryTest() throws Exception
  {
    replicationServer.getChangelogDB().setPurgeDelay(0);
@@ -190,29 +179,6 @@
    ECLCompatTestLimits(1,4,true);
  }
  @Test(enabled=false, dependsOnMethods = { "PrimaryTest"})
  public void TestWithTwoDomains() throws Exception
  {
    replicationServer.getChangelogDB().setPurgeDelay(0);
    // Test with a mix of domains, a mix of DSes
    ECLTwoDomains();
  }
  @Test(enabled=false, dependsOnMethods = { "PrimaryTest"})
  public void TestAfterChangelogTrim() throws Exception
  {
    // Test ECL after changelog trimming
    ECLAfterChangelogTrim();
  }
  @Test(enabled=true, dependsOnMethods = { "PrimaryTest"})
  public void TestAfterDomainIsRemoved() throws Exception
  {
    ECLAfterDomainIsRemoved();
  }
  @Test(enabled=true, dependsOnMethods = { "PrimaryTest"})
  public void TestWithAndWithoutControl() throws Exception
  {
@@ -226,27 +192,6 @@
    ECLCompatWriteReadAllOps(5);
  }
  @Test(enabled = true, dependsOnMethods = { "TestWithAndWithoutControl" })
  public void TestWithIncludeAttributes() throws Exception
  {
    ECLIncludeAttributes();
  }
  @Test(enabled=true, dependsOnMethods = { "PrimaryTest"})
  public void TestChangeTimeHeartBeat() throws Exception
  {
    ChangeTimeHeartbeatTest();
  }
  @Test(enabled=true, dependsOnMethods = { "PrimaryTest"})
  public void TestOperationalAttributesNotVisibleOutsideRootDSE() throws Exception
  {
    // Test that ECL Operational, virtual attributes are not visible
    // outside rootDSE. Next test will test access in RootDSE.
    // This one checks in data.
    ECLOperationalAttributesFailTest();
  }
  @Test(enabled=false, dependsOnMethods = { "PrimaryTest"})
  public void PrimaryFullTest() throws Exception
  {
@@ -279,10 +224,8 @@
    // Test all types of ops.
    ECLAllOps(); // Do not clean the db for the next test
    // Test that ECL Operational, virtual attributes are not visible
    // outside rootDSE. Next test will test access in RootDSE.
    // This one checks in data.
    ECLOperationalAttributesFailTest();
    // Test after this one will test access in RootDSE. This one checks in data.
    TestECLOperationalAttributesNotVisibleOutsideRootDSE();
    // First and last should be ok whenever a request has been done or not
    // in compat mode.
@@ -296,27 +239,20 @@
    ECLRemoteNonEmpty();
  }
  /** Persistent search with changesOnly request */
  @Test(enabled=false, groups="slow", dependsOnMethods = { "PrimaryTest"})
  public void FullTestPersistentSearchWithChangesOnlyRequest() throws Exception
  {
    // Persistent search with changesOnly request
    ECLPsearch(true, false);
  }
  /** Persistent search with init values request */
  @Test(enabled=false, groups="slow", dependsOnMethods = { "PrimaryTest"})
  public void FullTestPersistentSearchWithInitValuesRequest() throws Exception
  {
    // Persistent search with init values request
    ECLPsearch(false, false);
  }
  @Test(enabled=false, groups="slow", dependsOnMethods = { "PrimaryTest"})
  public void FullTestSimultaneousPersistentSearches() throws Exception
  {
    // Simultaneous psearches
    ECLSimultaneousPsearches();
  }
  // TODO:ECL Test SEARCH abandon and check everything shutdown and cleaned
  // TODO:ECL Test PSEARCH abandon and check everything shutdown and cleaned
  // TODO:ECL Test invalid DN in cookie returns UNWILLING + message
@@ -410,7 +346,9 @@
    assertEquals(ico.getErrorMessage().toMessage(), NOTE_SEARCH_CHANGELOG_INSUFFICIENT_PRIVILEGES.get());
  }
  private void ECLIsNotASupportedSuffix() throws Exception
  /** No RSDomain created yet => RS only case => ECL is not a supported. */
  @Test(enabled = true)
  public void TestECLIsNotASupportedSuffix() throws Exception
  {
    ECLCompatTestLimits(0,0, false);
  }
@@ -470,11 +408,15 @@
  }
  /**
   * Objectives
   *   - Test that everything is ok with changes on 2 suffixes
   * Procedure
   *   - From 1 remote ECL session,
   *   - Test simple update to be received from 2 suffixes
   * Objectives:
   * <ul>
   * <li>Test that everything is ok with changes on 2 suffixes</li>
   * </ul>
   * Procedure:
   * <ul>
   * <li>From 1 remote ECL session,</li>
   * <li>Test simple update to be received from 2 suffixes</li>
   * </ul>
   */
  private void ECLRemoteNonEmpty() throws Exception
  {
@@ -558,7 +500,7 @@
    debugInfo(tn, "Starting test\n\n");
    // root entry returned
    searchOnChangelog("(objectclass=*)", Collections.<String> emptySet(), createControls(""),
    searchOnChangelog("(objectclass=*)", Collections.<String> emptySet(), createCookieControl(""),
        1, ResultCode.SUCCESS, tn);
    debugInfo(tn, "Ending test successfully");
@@ -569,12 +511,11 @@
   * @param cookie The provided cookie.
   * @return The built list of controls.
   */
  private List<Control> createControls(String cookie) throws DirectoryException
  private List<Control> createCookieControl(String cookie) throws DirectoryException
  {
    final MultiDomainServerState state = new MultiDomainServerState(cookie);
    final List<Control> controls = new ArrayList<Control>(1);
    controls.add(new ExternalChangelogRequestControl(true, state));
    return controls;
    final Control cookieControl = new ExternalChangelogRequestControl(true, state);
    return newList(cookieControl);
  }
  /**
@@ -666,11 +607,16 @@
  }
  /**
   * From embedded ECL Search ECL with 4 messages on 2 suffixes from 2 brokers
   * From embedded ECL Search ECL with 4 messages on 2 suffixes from 2 brokers.
   * Test with a mix of domains, a mix of DSes.
   */
  private void ECLTwoDomains() throws Exception
  @Test(enabled=false, dependsOnMethods = { "PrimaryTest"})
  public void TestECLWithTwoDomains() throws Exception
  {
    String tn = "ECLTwoDomains";
    replicationServer.getChangelogDB().setPurgeDelay(0);
    String tn = "TestECLWithTwoDomains";
    debugInfo(tn, "Starting test");
    ReplicationBroker s1test = null;
@@ -880,7 +826,7 @@
      throws Exception
  {
    debugInfo(testName, "Search with cookie=[" + cookie + "] filter=[" + filterString + "]");
    return searchOnChangelog(filterString, ALL_ATTRIBUTES, createControls(cookie),
    return searchOnChangelog(filterString, ALL_ATTRIBUTES, createCookieControl(cookie),
        expectedNbEntries, expectedResultCode, testName);
  }
@@ -925,9 +871,10 @@
  }
  /** Test ECL content after replication changelogDB trimming */
  private void ECLAfterChangelogTrim() throws Exception
  @Test(enabled=false, dependsOnMethods = { "PrimaryTest"})
  public void testECLAfterChangelogTrim() throws Exception
  {
    String testName = "ECLAfterChangelogTrim";
    String testName = "testECLAfterChangelogTrim";
    debugInfo(testName, "Starting test");
    ReplicationBroker server01 = null;
@@ -992,9 +939,10 @@
  }
  /** Test ECL content after a domain has been removed. */
  private void ECLAfterDomainIsRemoved() throws Exception
  @Test(enabled=true, dependsOnMethods = { "PrimaryTest"})
  public void testECLAfterDomainIsRemoved() throws Exception
  {
    String testName = "ECLAfterDomainIsRemoved";
    String testName = "testECLAfterDomainIsRemoved";
    debugInfo(testName, "Starting test");
    ReplicationBroker server01 = null;
@@ -1131,7 +1079,7 @@
          baseUUID,
          entry.getObjectClassAttribute(),
          entry.getAttributes(),
          new ArrayList<Attribute>());
          Collections.<Attribute> emptyList());
      server01.publish(addMsg);
      debugInfo(tn, " publishes " + addMsg.getCSN());
@@ -1248,31 +1196,27 @@
    assertThat(actualDN).isEqualToIgnoringCase(expectedDN);
  }
  private List<String> getControls(String resultString)
  private List<String> getControls(String resultString) throws Exception
  {
    StringReader r=new StringReader(resultString);
    BufferedReader br=new BufferedReader(r);
    List<String> ctrlList = new ArrayList<String>();
    try {
      while(true) {
        String s = br.readLine();
        if(s == null)
        {
          break;
        }
        if(!s.startsWith("#"))
        {
          continue;
        }
        String[] a=s.split(": ");
        if(a.length != 2)
        {
          break;
        }
        ctrlList.add(a[1]);
    final BufferedReader br = new BufferedReader(new StringReader(resultString));
    final List<String> ctrlList = new ArrayList<String>();
    while (true)
    {
      final String s = br.readLine();
      if (s == null)
      {
        break;
      }
    } catch (IOException e) {
      assertEquals(0, 1, e.getMessage());
      if (!s.startsWith("#"))
      {
        continue;
      }
      final String[] a = s.split(": ");
      if (a.length != 2)
      {
        break;
      }
      ctrlList.add(a[1]);
    }
    return ctrlList;
  }
@@ -1432,7 +1376,7 @@
      // Creates cookie control
      String cookie = "";
      List<Control> controls = createControls(cookie);
      List<Control> controls = createCookieControl(cookie);
      if (compatMode)
      {
        cookie = null;
@@ -1574,7 +1518,7 @@
            createSearchRequest("(targetDN=*directpsearch*,o=test)", null);
        debugInfo(tn, "ACI test : sending search");
        message = new LDAPMessage(2, searchRequest, createControls(""));
        message = new LDAPMessage(2, searchRequest, createCookieControl(""));
        w.writeMessage(message);
        searchesDone=0;
@@ -1653,11 +1597,12 @@
  }
  /**
   * Test parallel simultaneous psearch with different filters.
   * Test parallel simultaneous persistent search with different filters.
   */
  private void ECLSimultaneousPsearches() throws Exception
  @Test(enabled = false, groups = "slow", dependsOnMethods = { "PrimaryTest" })
  public void FullTestSimultaneousPersistentSearches() throws Exception
  {
    String tn = "ECLSimultaneousPsearches";
    String tn = "FullTestSimultaneousPersistentSearches";
    debugInfo(tn, "Starting test \n\n");
    Socket s1 = null, s2 = null, s3 = null;
    ReplicationBroker server01 = null;
@@ -1723,7 +1668,7 @@
      // Creates cookie control
      String cookie = "";
      List<Control> controls = createControls(cookie);
      List<Control> controls = createCookieControl(cookie);
      if (compatMode)
      {
        cookie = null;
@@ -2162,9 +2107,10 @@
  /**
   * FIXME this test actually tests nothing: there are no asserts.
   */
  private void ChangeTimeHeartbeatTest() throws Exception
  @Test(enabled = true, dependsOnMethods = { "PrimaryTest" })
  public void testChangeTimeHeartbeat() throws Exception
  {
    String tn = "ChangeTimeHeartbeatTest";
    String tn = "testChangeTimeHeartbeat";
    debugInfo(tn, "Starting test");
    ReplicationBroker s1test = null;
    ReplicationBroker s2test = null;
@@ -2291,7 +2237,7 @@
          baseUUID,
          entry.getObjectClassAttribute(),
          entry.getAttributes(),
          new ArrayList<Attribute>());
          Collections.<Attribute> emptyList());
      server01.publish(addMsg);
      debugInfo(tn, " publishes " + addMsg.getCSN());
@@ -2603,9 +2549,13 @@
    debugInfo(tn, "Ending test with success");
  }
  private void ECLOperationalAttributesFailTest() throws Exception
  /**
   * Test that ECL Operational, virtual attributes are not visible outside rootDSE.
   */
  @Test(enabled = true, dependsOnMethods = { "PrimaryTest" })
  public void TestECLOperationalAttributesNotVisibleOutsideRootDSE() throws Exception
  {
    String tn = "ECLOperationalAttributesFailTest";
    String tn = "TestECLOperationalAttributesNotVisibleOutsideRootDSE";
    // The goal is to verify that the Changelog attributes are not
    // available in other entries. We u
    debugInfo(tn, "Starting test \n\n");
@@ -2622,9 +2572,7 @@
            0, // Time limit
            false, // Types only
            "(objectclass=*)",
            attributes,
            NO_CONTROL,
            null);
            attributes);
    waitOpResult(searchOp, ResultCode.SUCCESS);
    final List<SearchResultEntry> entries = searchOp.getSearchEntries();
@@ -2720,9 +2668,7 @@
        0, // Time limit
        false, // Types only
        "(objectclass=*)",
        attributes,
        NO_CONTROL,
        null);
        attributes);
    waitOpResult(searchOp, ResultCode.SUCCESS);
    return searchOp;
  }
@@ -2773,11 +2719,12 @@
  }
  /**
   * Test ECl entry attributes, and there configuration.
   * Test ECl entry attributes, and their configuration.
   */
  private void ECLIncludeAttributes() throws Exception
  @Test(enabled = true, dependsOnMethods = { "TestWithAndWithoutControl" })
  public void TestECLWithIncludeAttributes() throws Exception
  {
    String tn = "ECLIncludeAttributes";
    String tn = "TestECLWithIncludeAttributes";
    debugInfo(tn, "Starting test\n\n");
    final String backendId3 = "test3";
@@ -2952,9 +2899,7 @@
  private List<Modification> createMods(String attributeName, String valueString)
  {
    Attribute attr = Attributes.create(attributeName, valueString);
    List<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE, attr));
    return mods;
    return newList(new Modification(ModificationType.REPLACE, attr));
  }
  private Entry parseIncludedAttributes(SearchResultEntry resultEntry,
@@ -2969,8 +2914,7 @@
    return TestCaseUtils.makeEntry(ldif);
  }
  private void waitOpResult(Operation operation, ResultCode expectedResult)
      throws Exception
  private void waitOpResult(Operation operation, ResultCode expectedResult) throws Exception
  {
    int i = 0;
    while (operation.getResultCode() == ResultCode.UNDEFINED