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

jvergara
22.31.2009 53c232421f375fb7aec505cd3f152511aed47167
Control Panel fix for issue 4302 (Unexpected errors using single JNDI connection with SSL and multiple threads.)

This fix has two parts:

1. Modify the threading mechanism used to search the contents of an entry. From now only one thread is created to do this task. The result is that there is no need of interrupting threads and that the number of threads that are generated is limited.

2. When the server contents are read, check also if the user connection (the one used by the LDAP browser to read user data) works. If it is not the case, a message informing the user to provide authentication is displayed. This modification helps in the case we encounter other issues and does not force the user to reopen the control panel dialog (or to figure out that the workaround is to go to 'File->Server to Administer'.

This check is already done for the admin connection, so this is just a completion of that check.
3 files modified
239 ■■■■■ changed files
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/ControlPanelInfo.java 115 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/BrowseEntriesPanel.java 98 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/util/LDAPEntryReader.java 26 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/datamodel/ControlPanelInfo.java
@@ -605,70 +605,48 @@
        {
          reader = createNewConfigFromDirContextReader();
          ((ConfigFromDirContext)reader).readConfiguration(ctx);
          if (reader.getExceptions().size() > 0)
          boolean connectionWorks = checkConnections(ctx, userDataCtx);
          if (!connectionWorks)
          {
            // Check the connection
            boolean connectionWorks = false;
            int nMaxErrors = 5;
            for (int i=0; i< nMaxErrors && !connectionWorks; i++)
            if (isLocal)
            {
              try
              {
                Utilities.pingDirContext(ctx);
                connectionWorks = true;
              }
              catch (NamingException ne)
              {
                try
                {
                  Thread.sleep(400);
                }
                catch (Throwable t)
                {
                }
              }
              // Try with off-line info
              reader = createNewConfigFromFileReader();
              ((ConfigFromFile)reader).readConfiguration();
            }
            if (!connectionWorks)
            else
            {
              if (isLocal)
              {
                // Try with offline info
                reader = createNewConfigFromFileReader();
                ((ConfigFromFile)reader).readConfiguration();
              }
              else
              {
                desc.setStatus(
                    ServerDescriptor.ServerStatus.NOT_CONNECTED_TO_REMOTE);
                reader = null;
              }
              desc.setStatus(
                  ServerDescriptor.ServerStatus.NOT_CONNECTED_TO_REMOTE);
              reader = null;
            }
            try
            {
              ctx.close();
            }
            catch (Throwable t)
            {
            }
            this.ctx = null;
            if (connectionPool.isConnectionRegistered(userDataCtx))
            {
              try
              {
                ctx.close();
                connectionPool.unregisterConnection(userDataCtx);
              }
              catch (Throwable t)
              {
              }
              this.ctx = null;
              if (connectionPool.isConnectionRegistered(userDataCtx))
              {
                try
                {
                  connectionPool.unregisterConnection(userDataCtx);
                }
                catch (Throwable t)
                {
                }
              }
              try
              {
                userDataCtx.close();
              }
              catch (Throwable t)
              {
              }
              userDataCtx = null;
            }
            try
            {
              userDataCtx.close();
            }
            catch (Throwable t)
            {
            }
            userDataCtx = null;
          }
        }
      }
@@ -1341,4 +1319,35 @@
    }
    return isRunningOnServer;
  }
  private boolean checkConnections(InitialLdapContext ctx,
      InitialLdapContext userCtx)
  {
    // Check the connection
    boolean connectionWorks = false;
    int nMaxErrors = 5;
    for (int i=0; i< nMaxErrors && !connectionWorks; i++)
    {
      try
      {
        Utilities.pingDirContext(ctx);
        if (userCtx != null)
        {
          Utilities.pingDirContext(userCtx);
        }
        connectionWorks = true;
      }
      catch (NamingException ne)
      {
        try
        {
          Thread.sleep(400);
        }
        catch (Throwable t)
        {
        }
      }
    }
    return connectionWorks;
  }
}
opends/src/guitools/org/opends/guitools/controlpanel/ui/BrowseEntriesPanel.java
@@ -67,11 +67,13 @@
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.event.EntryReadErrorEvent;
@@ -149,8 +151,9 @@
  private boolean ignoreTreeSelectionEvents = false;
  private ArrayList<LDAPEntryReader> entryReaderQueue =
    new ArrayList<LDAPEntryReader>();
  private LDAPEntryReader entryReader;
  private Thread entryReaderThread;
  /**
   * {@inheritDoc}
@@ -523,12 +526,11 @@
          controller.findConnectionForDisplayedEntry(node);
        LDAPEntryReader reader = new LDAPEntryReader(dn, ctx);
        reader.addEntryReadListener(entryPane);
        cleanupReaderQueue();
        // Required to update the browser controller properly if the entry is
        // deleted.
        entryPane.setTreePath(path);
        reader.startBackgroundTask();
        entryReaderQueue.add(reader);
        stopCurrentReader();
        startReader(reader);
      }
      catch (Throwable t)
      {
@@ -541,7 +543,7 @@
    }
    else
    {
      cleanupReaderQueue();
      stopCurrentReader();
      if ((paths != null) && (paths.length > 1))
      {
        entryPane.multipleEntriesSelected();
@@ -553,26 +555,76 @@
    }
  }
  /**
   * Cleans up the reader queue (the queue where we store the entries that we
   * must read).
   *
   */
  private void cleanupReaderQueue()
  private void stopCurrentReader()
  {
    ArrayList<LDAPEntryReader> toRemove = new ArrayList<LDAPEntryReader>();
    for (LDAPEntryReader r : entryReaderQueue)
    if (entryReader != null)
    {
      if (r.isOver())
      {
        toRemove.add(r);
      }
      else
      {
        r.interrupt();
      }
      entryReader.setNotifyListeners(false);
    }
    entryReaderQueue.removeAll(toRemove);
  }
  /**
   * Starts the provider reader.
   * @param reader the LDAPEntryReader.
   */
  private void startReader(LDAPEntryReader reader)
  {
    entryReader = reader;
    if ((entryReaderThread == null) || !entryReaderThread.isAlive())
    {
      entryReaderThread = new Thread(new Runnable()
      {
        LDAPEntryReader reader;
        CustomSearchResult sr;
        Throwable t;
        public void run()
        {
          while (true)
          {
            try
            {
              synchronized (entryReaderThread)
              {
                while ((reader = entryReader) == null)
                {
                  entryReaderThread.wait();
                }
              }
              sr = null;
              t = null;
              try
              {
                sr = reader.processBackgroundTask();
              }
              catch (Throwable th)
              {
                t = th;
              }
              SwingUtilities.invokeAndWait(new Runnable()
              {
                public void run()
                {
                  reader.backgroundTaskCompleted(sr, t);
                  if (reader == entryReader)
                  {
                    entryReader = null;
                  }
                }
              });
            }
            catch (Throwable t)
            {
              entryReader = null;
            }
          }
        }
      });
      entryReaderThread.start();
    }
    synchronized (entryReaderThread)
    {
      entryReaderThread.notify();
    }
  }
  /**
opends/src/guitools/org/opends/guitools/controlpanel/util/LDAPEntryReader.java
@@ -52,6 +52,7 @@
  private InitialLdapContext ctx;
  private Set<EntryReadListener> listeners = new HashSet<EntryReadListener>();
  private boolean isOver;
  private boolean notifyListeners;
  /**
   * Constructor of the entry reader.
@@ -62,6 +63,7 @@
  {
    this.dn = dn;
    this.ctx = ctx;
    this.notifyListeners = true;
  }
  /**
@@ -102,7 +104,7 @@
  public void backgroundTaskCompleted(CustomSearchResult sr,
      Throwable throwable)
  {
    if (!isInterrupted())
    if (!isInterrupted() && isNotifyListeners())
    {
      if (throwable == null)
      {
@@ -117,6 +119,28 @@
  }
  /**
   * Returns whether this entry reader will notify the listeners once it is
   * over.
   * @return whether this entry reader will notify the listeners once it is
   * over.
   */
  public boolean isNotifyListeners()
  {
    return notifyListeners;
  }
  /**
   * Sets whether this entry reader will notify the listeners once it is
   * over.
   * @param notifyListeners whether this entry reader will notify the listeners
   * once it is over.
   */
  public void setNotifyListeners(boolean notifyListeners)
  {
    this.notifyListeners = notifyListeners;
  }
  /**
   * Returns <CODE>true</CODE> if the read process is over and
   * <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if the read process is over and