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

neil_a_wilson
28.07.2007 7130333653ea598d87fff1e80bb98e6b19e37c1a
Migrate the work queue configuration to the admin framework.

OpenDS Issue Number: 1838
3 files added
5 files modified
927 ■■■■ changed files
opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml 11 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/TraditionalWorkQueueConfiguration.xml 91 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/WorkQueueConfiguration.xml 75 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/WorkQueue.java 13 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/DirectoryServer.java 99 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/WorkQueueConfigManager.java 171 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/TraditionalWorkQueue.java 434 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ConfigMessages.java 33 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
@@ -360,6 +360,17 @@
      </cli:relation>
    </adm:profile>
  </adm:relation>
  <adm:relation name="work-queue">
    <adm:one-to-one />
    <adm:profile name="ldap">
      <ldap:rdn-sequence>cn=Work Queue,cn=config</ldap:rdn-sequence>
    </adm:profile>
    <adm:profile name="cli">
      <cli:relation>
        <cli:default-property name="work-queue-class" />
      </cli:relation>
    </adm:profile>
  </adm:relation>
  <adm:product-name>OpenDS Directory Server</adm:product-name>
  <adm:tag-definition name="logging">
    <adm:synopsis>Logging</adm:synopsis>
opends/src/admin/defn/org/opends/server/admin/std/TraditionalWorkQueueConfiguration.xml
New file
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
! CDDL HEADER START
!
! The contents of this file are subject to the terms of the
! Common Development and Distribution License, Version 1.0 only
! (the "License").  You may not use this file except in compliance
! with the License.
!
! You can obtain a copy of the license at
! trunk/opends/resource/legal-notices/OpenDS.LICENSE
! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
! See the License for the specific language governing permissions
! and limitations under the License.
!
! When distributing Covered Code, include this CDDL HEADER in each
! file and include the License file at
! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
! add the following below this CDDL HEADER, with the fields enclosed
! by brackets "[]" replaced with your own identifying information:
!      Portions Copyright [yyyy] [name of copyright owner]
!
! CDDL HEADER END
!
!
!      Portions Copyright 2007 Sun Microsystems, Inc.
! -->
<adm:managed-object name="traditional-work-queue"
plural-name="traditional-work-queues" extends="work-queue"
package="org.opends.server.admin.std"
xmlns:adm="http://www.opends.org/admin"
xmlns:ldap="http://www.opends.org/admin-ldap">
  <adm:synopsis>
    The
    <adm:user-friendly-name />
    is a type of work queue that uses a number of worker threads that watch a
    queue and pick up an operation to process whenever one becomes available.
  </adm:synopsis>
  <adm:profile name="ldap">
    <ldap:object-class>
      <ldap:oid>1.3.6.1.4.1.26027.1.2.73</ldap:oid>
      <ldap:name>ds-cfg-traditional-work-queue</ldap:name>
      <ldap:superior>ds-cfg-work-queue</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property name="num-worker-threads" mandatory="true">
    <adm:synopsis>
      The number of worker threads that should be used to process operations
      placed into the queue.
    </adm:synopsis>
    <adm:syntax>
      <adm:integer lower-limit="1" />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.73</ldap:oid>
        <ldap:name>ds-cfg-num-worker-threads</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="max-work-queue-capacity" mandatory="false">
    <adm:synopsis>
      The maximum number of queued operations that can be in the work queue at
      any given time.  If the work queue is already full and additional requests
      are received by the server, they will be rejected.
    </adm:synopsis>
    <adm:default-behavior>
      <adm:alias>
        <adm:synopsis>
          The work queue will not impose any limit on the number of operations
          that can be enqueued at any one time.
        </adm:synopsis>
      </adm:alias>
    </adm:default-behavior>
    <adm:syntax>
      <adm:integer lower-limit="0" />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.68</ldap:oid>
        <ldap:name>ds-cfg-max-work-queue-capacity</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opends/src/admin/defn/org/opends/server/admin/std/WorkQueueConfiguration.xml
New file
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
! CDDL HEADER START
!
! The contents of this file are subject to the terms of the
! Common Development and Distribution License, Version 1.0 only
! (the "License").  You may not use this file except in compliance
! with the License.
!
! You can obtain a copy of the license at
! trunk/opends/resource/legal-notices/OpenDS.LICENSE
! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
! See the License for the specific language governing permissions
! and limitations under the License.
!
! When distributing Covered Code, include this CDDL HEADER in each
! file and include the License file at
! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
! add the following below this CDDL HEADER, with the fields enclosed
! by brackets "[]" replaced with your own identifying information:
!      Portions Copyright [yyyy] [name of copyright owner]
!
! CDDL HEADER END
!
!
!      Portions Copyright 2007 Sun Microsystems, Inc.
! -->
<adm:managed-object name="work-queue"
plural-name="work-queues"
package="org.opends.server.admin.std"
xmlns:adm="http://www.opends.org/admin"
xmlns:ldap="http://www.opends.org/admin-ldap">
  <adm:synopsis>
    The
    <adm:user-friendly-name />
    is responsible for ensuring that requests received from clients are
    processed in a timely manner.  Whenever a connection handler receives a
    client request, it should be placed in the work queue so that it may be
    processed appropriately.
  </adm:synopsis>
  <adm:tag name="core"/>
  <adm:profile name="ldap">
    <ldap:object-class>
      <ldap:oid>1.3.6.1.4.1.26027.1.2.72</ldap:oid>
      <ldap:name>ds-cfg-work-queue</ldap:name>
      <ldap:superior>top</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property name="work-queue-class" mandatory="true">
    <adm:synopsis>
      The fully-qualified name of the Java class that provides the
      <adm:user-friendly-name />
      implementation.
    </adm:synopsis>
    <adm:syntax>
      <adm:java-class>
        <adm:instance-of>
          org.opends.server.api.WorkQueue
        </adm:instance-of>
      </adm:java-class>
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.276</ldap:oid>
        <ldap:name>ds-cfg-work-queue-class</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opends/src/server/org/opends/server/api/WorkQueue.java
@@ -28,7 +28,7 @@
import org.opends.server.config.ConfigEntry;
import org.opends.server.admin.std.server.WorkQueueCfg;
import org.opends.server.config.ConfigException;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
@@ -45,16 +45,17 @@
 * implementations, but in general it is assumed that one or more
 * worker threads will be associated with the queue and may be used to
 * process requests in parallel.
 *
 * @param  <T>  The type of configuration handled by this work queue.
 */
public abstract class WorkQueue
public abstract class WorkQueue<T extends WorkQueueCfg>
{
  /**
   * Initializes this work queue based on the information in the
   * provided configuration entry.
   *
   * @param  configEntry  The configuration entry that contains the
   *                      information to use to initialize this work
   *                      queue.
   * @param  configuration  The configuration to use to initialize
   *                        the work queue.
   *
   * @throws  ConfigException  If the provided configuration entry
   *                           does not have a valid work queue
@@ -65,7 +66,7 @@
   *                                   related to the server
   *                                   configuration.
   */
  public abstract void initializeWorkQueue(ConfigEntry configEntry)
  public abstract void initializeWorkQueue(T configuration)
         throws ConfigException, InitializationException;
opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -66,7 +66,6 @@
import org.opends.server.backends.RootDSEBackend;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.config.StringConfigAttribute;
import org.opends.server.config.JMXMBean;
import org.opends.server.extensions.ConfigFileHandler;
import org.opends.server.extensions.JMXAlertHandler;
@@ -1167,7 +1166,7 @@
      // Create and initialize the work queue.
      initializeWorkQueue();
      workQueue = new WorkQueueConfigManager().initializeWorkQueue();
      StartupPluginResult startupPluginResult =
@@ -7107,102 +7106,6 @@
  /**
   * Initializes the Directory Server work queue from the information in the
   * configuration.
   *
   * @throws  ConfigException  If the Directory Server configuration does not
   *                           have a valid work queue specification.
   *
   * @throws  InitializationException  If a problem occurs while attempting to
   *                                   initialize the work queue.
   */
  private void initializeWorkQueue()
          throws ConfigException, InitializationException
  {
    DN configEntryDN;
    try
    {
      configEntryDN = DN.decode(DN_WORK_QUEUE_CONFIG);
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      int    msgID   = MSGID_WORKQ_CANNOT_PARSE_DN;
      String message = getMessage(msgID, DN_WORK_QUEUE_CONFIG,
                                  stackTraceToSingleLineString(e));
      throw new InitializationException(msgID, message, e);
    }
    ConfigEntry configEntry = configHandler.getConfigEntry(configEntryDN);
    if (configEntry == null)
    {
      int    msgID   = MSGID_WORKQ_NO_CONFIG;
      String message = getMessage(msgID, DN_WORK_QUEUE_CONFIG);
      throw new ConfigException(msgID, message);
    }
    int msgID = MSGID_WORKQ_DESCRIPTION_CLASS;
    StringConfigAttribute classStub =
         new StringConfigAttribute(ATTR_WORKQ_CLASS, getMessage(msgID), true,
                                   false, true);
    StringConfigAttribute classAttr =
         (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
    if (classAttr == null)
    {
      msgID = MSGID_WORKQ_NO_CLASS_ATTR;
      String message = getMessage(msgID, DN_WORK_QUEUE_CONFIG,
                                  ATTR_WORKQ_CLASS);
      throw new ConfigException(msgID, message);
    }
    else
    {
      Class workQueueClass ;
      try
      {
        workQueueClass = DirectoryServer.loadClass(classAttr.activeValue());
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        msgID = MSGID_WORKQ_CANNOT_LOAD;
        String message = getMessage(msgID, classAttr.activeValue(),
                                    stackTraceToSingleLineString(e));
        throw new InitializationException(msgID, message, e);
      }
      try
      {
        workQueue = (WorkQueue) workQueueClass.newInstance();
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        msgID = MSGID_WORKQ_CANNOT_INSTANTIATE;
        String message = getMessage(msgID, classAttr.activeValue(),
                                    stackTraceToSingleLineString(e));
        throw new InitializationException(msgID, message, e);
      }
      workQueue.initializeWorkQueue(configEntry);
    }
  }
  /**
   * Starts the connection handlers defined in the Directory Server
   * Configuration.
   *
opends/src/server/org/opends/server/core/WorkQueueConfigManager.java
New file
@@ -0,0 +1,171 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.opends.server.admin.ClassPropertyDefinition;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.meta.WorkQueueCfgDefn;
import org.opends.server.admin.std.server.WorkQueueCfg;
import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.api.WorkQueue;
import org.opends.server.config.ConfigException;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * This class defines a utility that will be used to manage the Directory Server
 * work queue.
 */
public class WorkQueueConfigManager
       implements ConfigurationChangeListener<WorkQueueCfg>
{
  /**
   * Creates a new instance of this work queue config manager.
   */
  public WorkQueueConfigManager()
  {
    // No implementation is required.
  }
  /**
   * Initializes the Directory Server's work queue.  This should only be called
   * at server startup.
   *
   * @return  WorkQueue  The initialized work queue that should be used by the
   *                     server.
   *
   * @throws  ConfigException  If a configuration problem causes the work queue
   *                           initialization process to fail.
   *
   * @throws  InitializationException  If a problem occurs while initializing
   *                                   the work queue that is not related to the
   *                                   server configuration.
   */
  public WorkQueue initializeWorkQueue()
         throws ConfigException, InitializationException
  {
    // Get the root configuration object.
    ServerManagementContext managementContext =
         ServerManagementContext.getInstance();
    RootCfg rootConfiguration =
         managementContext.getRootConfiguration();
    // Get the work queue configuration and register with it as a change
    // listener.
    WorkQueueCfg workQueueConfig = rootConfiguration.getWorkQueue();
    workQueueConfig.addChangeListener(this);
    // Get the work queue class, and load and instantiate an instance of it
    // using that configuration.
    WorkQueueCfgDefn definition = WorkQueueCfgDefn.getInstance();
    ClassPropertyDefinition propertyDefinition =
         definition.getWorkQueueClassPropertyDefinition();
    Class<? extends WorkQueue> workQueueClass =
         propertyDefinition.loadClass(workQueueConfig.getWorkQueueClass(),
                                      WorkQueue.class);
    try
    {
      WorkQueue workQueue = workQueueClass.newInstance();
      Method method = workQueue.getClass().getMethod("initializeWorkQueue",
           workQueueConfig.definition().getServerConfigurationClass());
      method.invoke(workQueue, workQueueConfig);
      return workQueue;
    }
    catch (Exception e)
    {
      int msgID = MSGID_CONFIG_WORK_QUEUE_INITIALIZATION_FAILED;
      String message = getMessage(msgID, workQueueConfig.getWorkQueueClass(),
                                  String.valueOf(workQueueConfig.dn()),
                                  stackTraceToSingleLineString(e));
      throw new InitializationException(msgID, message, e);
    }
  }
  /**
   * {@inheritDoc}
   */
  public boolean isConfigurationChangeAcceptable(WorkQueueCfg configuration,
                      List<String> unacceptableReasons)
  {
    // Changes to the work queue configuration will always be acceptable to this
    // generic implementation.
    return true;
  }
  /**
   * {@inheritDoc}
   */
  public ConfigChangeResult applyConfigurationChange(WorkQueueCfg configuration)
  {
    ResultCode        resultCode          = ResultCode.SUCCESS;
    boolean           adminActionRequired = false;
    ArrayList<String> messages            = new ArrayList<String>();
    // If the work queue class has been changed, then we should warn the user
    // that it won't take effect until the server is restarted.
    WorkQueue workQueue = DirectoryServer.getWorkQueue();
    String workQueueClass = configuration.getWorkQueueClass();
    if (! workQueueClass.equals(workQueue.getClass().getName()))
    {
      int msgID = MSGID_CONFIG_WORK_QUEUE_CLASS_CHANGE_REQUIRES_RESTART;
      messages.add(getMessage(msgID, workQueue.getClass().getName(),
                              workQueueClass));
      adminActionRequired = true;
    }
    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
  }
}
opends/src/server/org/opends/server/extensions/TraditionalWorkQueue.java
@@ -37,12 +37,10 @@
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import org.opends.server.api.ConfigurableComponent;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.TraditionalWorkQueueCfg;
import org.opends.server.api.WorkQueue;
import org.opends.server.config.ConfigAttribute;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.config.IntegerConfigAttribute;
import org.opends.server.core.DirectoryServer;
import org.opends.server.monitors.TraditionalWorkQueueMonitor;
import org.opends.server.types.CancelRequest;
@@ -71,8 +69,8 @@
 * Directory Server work queue.
 */
public class TraditionalWorkQueue
       extends WorkQueue
       implements ConfigurableComponent
       extends WorkQueue<TraditionalWorkQueueCfg>
       implements ConfigurationChangeListener<TraditionalWorkQueueCfg>
{
  /**
   * The tracer object for the debug logger.
@@ -145,7 +143,8 @@
  /**
   * {@inheritDoc}
   */
  public void initializeWorkQueue(ConfigEntry configEntry)
  @Override()
  public void initializeWorkQueue(TraditionalWorkQueueCfg configuration)
         throws ConfigException, InitializationException
  {
    shutdownRequested = false;
@@ -155,104 +154,14 @@
    queueLock         = new ReentrantLock();
    // Register to be notified of any configuration changes.
    configuration.addTraditionalChangeListener(this);
    // Get the necessary configuration from the provided entry.
    configEntryDN = configEntry.getDN();
    int msgID = MSGID_CONFIG_WORK_QUEUE_DESCRIPTION_NUM_THREADS;
    IntegerConfigAttribute numThreadsStub =
      new IntegerConfigAttribute(ATTR_NUM_WORKER_THREADS, getMessage(msgID),
                                 true, false, false, true, 1, false, 0,
                                 DEFAULT_NUM_WORKER_THREADS);
    try
    {
      IntegerConfigAttribute numThreadsAttr =
        (IntegerConfigAttribute)
        configEntry.getConfigAttribute(numThreadsStub);
      if (numThreadsAttr == null)
      {
        numWorkerThreads = DEFAULT_NUM_WORKER_THREADS;
      }
      else
      {
        numWorkerThreads = numThreadsAttr.activeIntValue();
        if (numWorkerThreads <= 0)
        {
          //This is not valid.  The number of worker threads must be a positive
          // integer.
          msgID = MSGID_CONFIG_WORK_QUEUE_NUM_THREADS_INVALID_VALUE;
          String message = getMessage(msgID,
                                      String.valueOf(configEntryDN),
                                      numWorkerThreads);
          logError(ErrorLogCategory.CONFIGURATION,
                   ErrorLogSeverity.SEVERE_WARNING, message, msgID);
          numWorkerThreads = DEFAULT_NUM_WORKER_THREADS;
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_CONFIG_WORK_QUEUE_CANNOT_DETERMINE_NUM_WORKER_THREADS;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  String.valueOf(e));
      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
               message, msgID);
      numWorkerThreads = DEFAULT_NUM_WORKER_THREADS;
    }
    msgID = MSGID_CONFIG_WORK_QUEUE_DESCRIPTION_MAX_CAPACITY;
    IntegerConfigAttribute capacityStub =
      new IntegerConfigAttribute(ATTR_MAX_WORK_QUEUE_CAPACITY,
                                 getMessage(msgID), true, false, false, true,
                                 0, false, 0,
                                 DEFAULT_MAX_WORK_QUEUE_CAPACITY);
    try
    {
      IntegerConfigAttribute capacityAttr =
        (IntegerConfigAttribute)
        configEntry.getConfigAttribute(capacityStub);
      if (capacityAttr == null)
      {
        maxCapacity = DEFAULT_MAX_WORK_QUEUE_CAPACITY;
      }
      else
      {
        maxCapacity = capacityAttr.activeIntValue();
        if (maxCapacity < 0)
        {
          // This is not valid.  The maximum capacity must be greater than or
          // equal to zero.
          msgID = MSGID_CONFIG_WORK_QUEUE_CAPACITY_INVALID_VALUE;
          String message = getMessage(msgID, String.valueOf(configEntryDN),
                                      maxCapacity);
          logError(ErrorLogCategory.CONFIGURATION,
                   ErrorLogSeverity.SEVERE_WARNING, message, msgID);
          maxCapacity = DEFAULT_MAX_WORK_QUEUE_CAPACITY;
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_CONFIG_WORK_QUEUE_CANNOT_DETERMINE_QUEUE_CAPACITY;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  String.valueOf(e));
      logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
               message, msgID);
      maxCapacity = DEFAULT_MAX_WORK_QUEUE_CAPACITY;
    }
    configEntryDN    = configuration.dn();
    numWorkerThreads = configuration.getNumWorkerThreads();
    maxCapacity      = configuration.getMaxWorkQueueCapacity();
    // Create the actual work queue.
@@ -279,10 +188,6 @@
    }
    // Register with the Directory Server as a configurable component.
    DirectoryServer.registerConfigurableComponent(this);
    // Create and register a monitor provider for the work queue.
    try
    {
@@ -299,7 +204,7 @@
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_CONFIG_WORK_QUEUE_CANNOT_CREATE_MONITOR;
      int msgID = MSGID_CONFIG_WORK_QUEUE_CANNOT_CREATE_MONITOR;
      String message = getMessage(msgID, TraditionalWorkQueueMonitor.class,
                                  String.valueOf(e));
      logError(ErrorLogCategory.CORE_SERVER, ErrorLogSeverity.SEVERE_ERROR,
@@ -312,6 +217,7 @@
  /**
   * {@inheritDoc}
   */
  @Override()
  public void finalizeWorkQueue(String reason)
  {
    shutdownRequested = true;
@@ -389,6 +295,7 @@
   *                              down or the pending operation queue is already
   *                              at its maximum capacity).
   */
  @Override()
  public void submitOperation(Operation operation)
         throws DirectoryException
  {
@@ -659,291 +566,29 @@
  /**
   * Retrieves the DN of the configuration entry with which this component is
   * associated.
   *
   * @return  The DN of the configuration entry with which this component is
   *          associated.
   * {@inheritDoc}
   */
  public DN getConfigurableComponentEntryDN()
  {
    return configEntryDN;
  }
  /**
   * Retrieves the set of configuration attributes that are associated with this
   * configurable component.
   *
   * @return  The set of configuration attributes that are associated with this
   *          configurable component.
   */
  public List<ConfigAttribute> getConfigurationAttributes()
  {
    LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
    int msgID = MSGID_CONFIG_WORK_QUEUE_DESCRIPTION_NUM_THREADS;
    IntegerConfigAttribute numThreadsAttr =
      new IntegerConfigAttribute(ATTR_NUM_WORKER_THREADS, getMessage(msgID),
                                 true, false, false, true, 1, false, 0,
                                 workerThreads.size());
    attrList.add(numThreadsAttr);
    msgID = MSGID_CONFIG_WORK_QUEUE_DESCRIPTION_MAX_CAPACITY;
    IntegerConfigAttribute capacityAttr =
      new IntegerConfigAttribute(ATTR_MAX_WORK_QUEUE_CAPACITY,
                                 getMessage(msgID), true, false, false, true,
                                 0, false, 0, maxCapacity);
    attrList.add(capacityAttr);
    return attrList;
  }
  /**
   * Indicates whether the provided configuration entry has an acceptable
   * configuration for this component.  If it does not, then detailed
   * information about the problem(s) should be added to the provided list.
   *
   * @param  configEntry          The configuration entry for which to make the
   *                              determination.
   * @param  unacceptableReasons  A list that can be used to hold messages about
   *                              why the provided entry does not have an
   *                              acceptable configuration.
   *
   * @return  <CODE>true</CODE> if the provided entry has an acceptable
   *          configuration for this component, or <CODE>false</CODE> if not.
   */
  public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
  @Override()
  public boolean isConfigurationChangeAcceptable(
                      TraditionalWorkQueueCfg configuration,
                                            List<String> unacceptableReasons)
  {
    boolean configIsAcceptable = true;
    // Check the configuration for the number of worker threads.
    int msgID = MSGID_CONFIG_WORK_QUEUE_DESCRIPTION_NUM_THREADS;
    IntegerConfigAttribute numThreadsStub =
      new IntegerConfigAttribute(ATTR_NUM_WORKER_THREADS, getMessage(msgID),
                                 true, false, false, true, 1, false, 0,
                                 workerThreads.size());
    try
    {
      IntegerConfigAttribute numThreadsAttr =
        (IntegerConfigAttribute)
        configEntry.getConfigAttribute(numThreadsStub);
      if (numThreadsAttr == null)
      {
        // This means that the entry doesn't contain the attribute.  This is
        // fine, since we'll just use the default.
      }
      else
      {
        int numWorkerThreads = numThreadsAttr.activeIntValue();
        if (numWorkerThreads <= 0)
        {
          //This is not valid.  The number of worker threads must be a positive
          // integer.
          msgID = MSGID_CONFIG_WORK_QUEUE_NUM_THREADS_INVALID_VALUE;
          String message = getMessage(msgID,
                                      String.valueOf(configEntryDN),
                                      numWorkerThreads);
          unacceptableReasons.add(message);
          configIsAcceptable = false;
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_CONFIG_WORK_QUEUE_CANNOT_DETERMINE_NUM_WORKER_THREADS;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  String.valueOf(e));
      unacceptableReasons.add(message);
      configIsAcceptable = false;
    }
    // Check the configuration for the maximum work queue capacity.
    msgID = MSGID_CONFIG_WORK_QUEUE_DESCRIPTION_MAX_CAPACITY;
    IntegerConfigAttribute capacityStub =
      new IntegerConfigAttribute(ATTR_MAX_WORK_QUEUE_CAPACITY,
                                 getMessage(msgID), true, false, false, true,
                                 0, false, 0,
                                 maxCapacity);
    try
    {
      IntegerConfigAttribute capacityAttr =
        (IntegerConfigAttribute)
        configEntry.getConfigAttribute(capacityStub);
      if (capacityAttr == null)
      {
        //This means that the entry doesn't contain the attribute.  This is
        // fine, since we'll just use the default.
      }
      else
      {
        int newMaxCapacity = capacityAttr.activeIntValue();
        if (newMaxCapacity < 0)
        {
          // This is not valid.  The maximum capacity must be greater than or
          // equal to zero.
          msgID = MSGID_CONFIG_WORK_QUEUE_CAPACITY_INVALID_VALUE;
          String message = getMessage(msgID, String.valueOf(configEntryDN),
                                      newMaxCapacity);
          unacceptableReasons.add(message);
          configIsAcceptable = false;
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_CONFIG_WORK_QUEUE_CANNOT_DETERMINE_QUEUE_CAPACITY;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  String.valueOf(e));
      unacceptableReasons.add(message);
      configIsAcceptable = false;
    }
    return configIsAcceptable;
    // The provided configuration will always be acceptable.
    return true;
  }
  /**
   * Makes a best-effort attempt to apply the configuration contained in the
   * provided entry.  Information about the result of this processing should be
   * added to the provided message list.  Information should always be added to
   * this list if a configuration change could not be applied.  If detailed
   * results are requested, then information about the changes applied
   * successfully (and optionally about parameters that were not changed) should
   * also be included.
   *
   * @param  configEntry      The entry containing the new configuration to
   *                          apply for this component.
   * @param  detailedResults  Indicates whether detailed information about the
   *                          processing should be added to the list.
   *
   * @return  Information about the result of the configuration update.
   * {@inheritDoc}
   */
  public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
                                                  boolean detailedResults)
  @Override()
  public ConfigChangeResult applyConfigurationChange(
                                 TraditionalWorkQueueCfg configuration)
  {
    ArrayList<String> resultMessages = new ArrayList<String>();
    int newNumThreads;
    int newMaxCapacity;
    // Check the configuration for the number of worker threads.
    int msgID = MSGID_CONFIG_WORK_QUEUE_DESCRIPTION_NUM_THREADS;
    IntegerConfigAttribute numThreadsStub =
      new IntegerConfigAttribute(ATTR_NUM_WORKER_THREADS, getMessage(msgID),
                                 true, false, false, true, 1, false, 0,
                                 workerThreads.size());
    try
    {
      IntegerConfigAttribute numThreadsAttr =
        (IntegerConfigAttribute)
        configEntry.getConfigAttribute(numThreadsStub);
      if (numThreadsAttr == null)
      {
        // This means that the entry doesn't contain the attribute.  This is
        // fine, since we'll just use the default.
        newNumThreads = DEFAULT_NUM_WORKER_THREADS;
      }
      else
      {
        newNumThreads = numThreadsAttr.activeIntValue();
        if (newNumThreads <= 0)
        {
          //This is not valid.  The number of worker threads must be a positive
          // integer.  This should never happen since it should be filtered out
          // by the hasAcceptableConfiguration method, but if it does for some
          // reason then handle it.
          msgID = MSGID_CONFIG_WORK_QUEUE_NUM_THREADS_INVALID_VALUE;
          String message = getMessage(msgID,
                                      String.valueOf(configEntryDN),
                                      newNumThreads);
          resultMessages.add(message);
          newNumThreads = DEFAULT_NUM_WORKER_THREADS;
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_CONFIG_WORK_QUEUE_CANNOT_DETERMINE_NUM_WORKER_THREADS;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  String.valueOf(e));
      resultMessages.add(message);
      newNumThreads = DEFAULT_NUM_WORKER_THREADS;
    }
    // Check the configuration for the maximum work queue capacity.
    msgID = MSGID_CONFIG_WORK_QUEUE_DESCRIPTION_MAX_CAPACITY;
    IntegerConfigAttribute capacityStub =
      new IntegerConfigAttribute(ATTR_MAX_WORK_QUEUE_CAPACITY,
                                 getMessage(msgID), true, false, false, true,
                                 0, false, 0,
                                 maxCapacity);
    try
    {
      IntegerConfigAttribute capacityAttr =
        (IntegerConfigAttribute)
        configEntry.getConfigAttribute(capacityStub);
      if (capacityAttr == null)
      {
        //This means that the entry doesn't contain the attribute.  This is
        // fine, since we'll just use the default.
        newMaxCapacity = DEFAULT_MAX_WORK_QUEUE_CAPACITY;
      }
      else
      {
        newMaxCapacity = capacityAttr.activeIntValue();
        if (newMaxCapacity < 0)
        {
          // This is not valid.  The maximum capacity must be greater than or
          // equal to zero.
          msgID = MSGID_CONFIG_WORK_QUEUE_CAPACITY_INVALID_VALUE;
          String message = getMessage(msgID, String.valueOf(configEntryDN),
                                      newMaxCapacity);
          resultMessages.add(message);
          newMaxCapacity = DEFAULT_MAX_WORK_QUEUE_CAPACITY;
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      msgID = MSGID_CONFIG_WORK_QUEUE_CANNOT_DETERMINE_QUEUE_CAPACITY;
      String message = getMessage(msgID, String.valueOf(configEntryDN),
                                  String.valueOf(e));
      resultMessages.add(message);
      newMaxCapacity = DEFAULT_MAX_WORK_QUEUE_CAPACITY;
    }
    int newNumThreads  = configuration.getNumWorkerThreads();
    int newMaxCapacity = configuration.getMaxWorkQueueCapacity();
    // Apply a change to the number of worker threads if appropriate.
@@ -965,25 +610,10 @@
            t.start();
          }
          if (detailedResults)
          {
            msgID = MSGID_CONFIG_WORK_QUEUE_CREATED_THREADS;
            String message = getMessage(msgID, threadsToAdd, newNumThreads);
            resultMessages.add(message);
          }
          killThreads = false;
        }
        else
        {
          if (detailedResults)
          {
            msgID = MSGID_CONFIG_WORK_QUEUE_DESTROYING_THREADS;
            String message = getMessage(msgID, Math.abs(threadsToAdd),
                                        newNumThreads);
            resultMessages.add(message);
          }
          killThreads = true;
        }
@@ -1058,13 +688,6 @@
          }
        }
        if (detailedResults)
        {
          msgID = MSGID_CONFIG_WORK_QUEUE_NEW_CAPACITY;
          String message = getMessage(msgID, newMaxCapacity);
          resultMessages.add(message);
        }
        maxCapacity = newMaxCapacity;
      }
      catch (Exception e)
@@ -1089,6 +712,7 @@
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean isIdle()
  {
    if (opQueue.size() > 0)
opends/src/server/org/opends/server/messages/ConfigMessages.java
@@ -6800,6 +6800,30 @@
  /**
   * The message ID for the message that will be used if an error occurs while
   * initializing the Directory Server work queue.  This takes three arguments,
   * which are the name of the class providing the work queue implementation,
   * the DN of the configuration entry, and a message explaining the problem
   * that occurred.
   */
  public static final int MSGID_CONFIG_WORK_QUEUE_INITIALIZATION_FAILED =
       CATEGORY_MASK_CONFIG | SEVERITY_MASK_SEVERE_ERROR | 674;
  /**
   * The message ID for the message that indicates the server needs to be
   * restarted in order for changes to the work queue class to take effect.
   * This takes two arguments, which are the names of the old and new work queue
   * class.
   */
  public static final int
       MSGID_CONFIG_WORK_QUEUE_CLASS_CHANGE_REQUIRES_RESTART =
            CATEGORY_MASK_CONFIG | SEVERITY_MASK_INFORMATIONAL | 675;
  /**
   * Associates a set of generic messages with the message IDs defined in this
@@ -7577,6 +7601,15 @@
                    "instance of class %s to use as a monitor provider for " +
                    "the Directory Server work queue:  %s.  No monitor " +
                    "information will be available for the work queue");
    registerMessage(MSGID_CONFIG_WORK_QUEUE_INITIALIZATION_FAILED,
                    "Unable to initialize an instance of class %s as a work " +
                    "queue as specified in configuration entry %s:  %s");
    registerMessage(MSGID_CONFIG_WORK_QUEUE_CLASS_CHANGE_REQUIRES_RESTART,
                    "The class used to provide the Directory Server work " +
                    "queue implementation has been changed from %s to %s, " +
                    "but this change will not take effect until the server " +
                    "is restarted");
   registerMessage(MSGID_CONFIG_DESCRIPTION_BACKEND_DIRECTORY,
                   "The name of the directory in which backend database " +