001/*
002 * Copyright 2008-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2008-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk.unboundidds.monitors;
037
038
039
040import java.util.Collections;
041import java.util.LinkedHashMap;
042import java.util.Map;
043
044import com.unboundid.ldap.sdk.Entry;
045import com.unboundid.util.NotMutable;
046import com.unboundid.util.NotNull;
047import com.unboundid.util.Nullable;
048import com.unboundid.util.StaticUtils;
049import com.unboundid.util.ThreadSafety;
050import com.unboundid.util.ThreadSafetyLevel;
051
052import static com.unboundid.ldap.sdk.unboundidds.monitors.MonitorMessages.*;
053
054
055
056/**
057 * This class defines a monitor entry that provides information about the state
058 * of the UnboundID work queue.  This has replaced the traditional work queue as
059 * the default work queue implementation used by the Directory Server
060 * <BR>
061 * <BLOCKQUOTE>
062 *   <B>NOTE:</B>  This class, and other classes within the
063 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
064 *   supported for use against Ping Identity, UnboundID, and
065 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
066 *   for proprietary functionality or for external specifications that are not
067 *   considered stable or mature enough to be guaranteed to work in an
068 *   interoperable way with other types of LDAP servers.
069 * </BLOCKQUOTE>
070 * <BR>
071 * The monitor information that it may make available includes:
072 * <UL>
073 *   <LI>The number of requests that were rejected because the work queue was
074 *       already at its maximum capacity.</LI>
075 *   <LI>The number of operations currently held in the work queue waiting to be
076 *       picked for processing by a worker thread.</LI>
077 *   <LI>The average number of operations held in the work queue since startup
078 *       as observed from periodic polling.</LI>
079 *   <LI>The maximum number of operations held in the work queue at any time
080 *       since startup as observed from periodic polling.</LI>
081 * </UL>
082 * The server should present at most one UnboundID work queue monitor entry.
083 * It can be retrieved using the
084 * {@link MonitorManager#getUnboundIDWorkQueueMonitorEntry} method.  This entry
085 * provides specific methods for accessing information about the state of
086 * the work queue (e.g., the
087 * {@link UnboundIDWorkQueueMonitorEntry#getCurrentSize} method may be used
088 * to retrieve the number of operations currently held in the work queue).
089 * Alternately, this information may be accessed using the generic API.  See the
090 * {@link MonitorManager} class documentation for an example that demonstrates
091 * the use of the generic API for accessing monitor data.
092 */
093@NotMutable()
094@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
095public final class UnboundIDWorkQueueMonitorEntry
096       extends MonitorEntry
097{
098  /**
099   * The structural object class used in LDAP statistics monitor entries.
100   */
101  @NotNull static final String UNBOUNDID_WORK_QUEUE_MONITOR_OC =
102       "ds-unboundid-work-queue-monitor-entry";
103
104
105
106  /**
107   * The name of the attribute that contains the average worker thread percent
108   * busy.
109   */
110  @NotNull private static final String ATTR_AVERAGE_QUEUE_TIME_MILLIS =
111       "average-operation-queue-time-millis";
112
113
114
115  /**
116   * The name of the attribute that contains the average worker thread percent
117   * busy.
118   */
119  @NotNull private static final String ATTR_AVERAGE_PCT_BUSY =
120       "average-worker-thread-percent-busy";
121
122
123
124  /**
125   * The name of the attribute that contains the average observed work queue
126   * size.
127   */
128  @NotNull private static final String ATTR_AVERAGE_SIZE = "average-queue-size";
129
130
131
132  /**
133   * The name of the attribute that contains the current work queue size.
134   */
135  @NotNull private static final String ATTR_CURRENT_PCT_BUSY =
136       "current-worker-thread-percent-busy";
137
138
139
140  /**
141   * The name of the attribute that contains the current work queue size.
142   */
143  @NotNull private static final String ATTR_CURRENT_SIZE = "current-queue-size";
144
145
146
147  /**
148   * The name of the attribute that contains the maximum observed work queue
149   * size.
150   */
151  @NotNull private static final String ATTR_MAX_SIZE = "max-queue-size";
152
153
154
155  /**
156   * The name of the attribute that contains the maximum worker thread percent
157   * busy.
158   */
159  @NotNull private static final String ATTR_MAX_PCT_BUSY =
160       "max-worker-thread-percent-busy";
161
162
163
164  /**
165   * The name of the attribute that contains the number of busy worker threads.
166   */
167  @NotNull private static final String ATTR_NUM_BUSY_WORKER_THREADS =
168       "num-busy-worker-threads";
169
170
171
172  /**
173   * The name of the attribute that contains the number of worker threads.
174   */
175  @NotNull private static final String ATTR_NUM_WORKER_THREADS =
176       "num-worker-threads";
177
178
179
180  /**
181   * The name of the attribute that contains the average worker thread percent
182   * busy.
183   */
184  @NotNull private static final String ATTR_RECENT_AVERAGE_SIZE =
185       "recent-average-queue-size";
186
187
188
189  /**
190   * The name of the attribute that contains the average worker thread percent
191   * busy.
192   */
193  @NotNull private static final String ATTR_RECENT_QUEUE_TIME_MILLIS =
194       "recent-operation-queue-time-millis";
195
196
197
198  /**
199   * The name of the attribute that contains the recent worker thread percent
200   * busy.
201   */
202  @NotNull private static final String ATTR_RECENT_PCT_BUSY =
203       "recent-worker-thread-percent-busy";
204
205
206
207  /**
208   * The name of the attribute that contains the total number of requests that
209   * have been rejected because the work queue was full.
210   */
211  @NotNull private static final String ATTR_REQUESTS_REJECTED =
212       "rejected-count";
213
214
215
216  /**
217   * The name of the attribute that contains the total number of requests that
218   * have were stolen from their primary queue by a worker thread associated
219   * with a different queue.
220   */
221  @NotNull private static final String ATTR_REQUESTS_STOLEN = "stolen-count";
222
223
224
225  /**
226   * The name of the attribute that contains the current size of the work queue
227   * reserved for operations processed as part of administrative sessions.
228   */
229  @NotNull private static final String ATTR_CURRENT_ADMIN_QUEUE_SIZE =
230       "current-administrative-session-queue-size";
231
232
233
234  /**
235   * The name of the attribute that contains the number of worker threads that
236   * are currently busy processing operations as part of an administrative
237   * session.
238   */
239  @NotNull private static final String ATTR_MAX_ADMIN_SESSION_QUEUE_SIZE =
240       "max-administrative-session-queue-size";
241
242
243
244  /**
245   * The name of the attribute that contains the total number of worker threads
246   * reserved for processing operations that are part of an administrative
247   * session.
248   */
249  @NotNull private static final String ATTR_NUM_ADMIN_WORKER_THREADS =
250       "num-administrative-session-worker-threads";
251
252
253
254  /**
255   * The name of the attribute that contains the number of worker threads that
256   * are currently busy processing operations as part of an administrative
257   * session.
258   */
259  @NotNull private static final String ATTR_NUM_BUSY_ADMIN_WORKER_THREADS =
260       "num-busy-administrative-session-worker-threads";
261
262
263
264  /**
265   * The serial version UID for this serializable class.
266   */
267  private static final long serialVersionUID = -304216058351812232L;
268
269
270
271  // The average queue time in milliseconds.
272  @Nullable private final Long averageQueueTimeMillis;
273
274  // The average worker thread percent busy.
275  @Nullable private final Long averagePercentBusy;
276
277  // The average work queue size.
278  @Nullable private final Long averageSize;
279
280  // The current administrative session work queue size.
281  @Nullable private final Long currentAdminSize;
282
283  // The current work queue size.
284  @Nullable private final Long currentSize;
285
286  // The current worker thread percent busy.
287  @Nullable private final Long currentPercentBusy;
288
289  // The maximum administrative session work queue size.
290  @Nullable private final Long maxAdminSize;
291
292  // The maximum worker thread percent busy.
293  @Nullable private final Long maxPercentBusy;
294
295  // The maximum work queue size.
296  @Nullable private final Long maxSize;
297
298  // The number of administrative session worker threads.
299  @Nullable private final Long numAdminWorkerThreads;
300
301  // The number of busy worker threads.
302  @Nullable private final Long numBusyWorkerThreads;
303
304  // The number of busy administrative session worker threads.
305  @Nullable private final Long numBusyAdminWorkerThreads;
306
307  // The number of worker threads.
308  @Nullable private final Long numWorkerThreads;
309
310  // The recent average work queue size.
311  @Nullable private final Long recentAverageSize;
312
313  // The recent queue time in milliseconds.
314  @Nullable private final Long recentQueueTimeMillis;
315
316  // The recent worker thread percent busy.
317  @Nullable private final Long recentPercentBusy;
318
319  // The total number of requests rejected due to a full work queue.
320  @Nullable private final Long requestsRejected;
321
322  // The total number of requests rejected due to a full work queue.
323  @Nullable private final Long requestsStolen;
324
325
326
327  /**
328   * Creates a new UnboundID work queue monitor entry from the provided entry.
329   *
330   * @param  entry  The entry to be parsed as a traditional work queue monitor
331   *                entry.  It must not be {@code null}.
332   */
333  public UnboundIDWorkQueueMonitorEntry(@NotNull final Entry entry)
334  {
335    super(entry);
336
337    averageSize               = getLong(ATTR_AVERAGE_SIZE);
338    currentSize               = getLong(ATTR_CURRENT_SIZE);
339    recentAverageSize         = getLong(ATTR_RECENT_AVERAGE_SIZE);
340    maxSize                   = getLong(ATTR_MAX_SIZE);
341    requestsRejected          = getLong(ATTR_REQUESTS_REJECTED);
342    requestsStolen            = getLong(ATTR_REQUESTS_STOLEN);
343    numBusyWorkerThreads      = getLong(ATTR_NUM_BUSY_WORKER_THREADS);
344    numWorkerThreads          = getLong(ATTR_NUM_WORKER_THREADS);
345    currentPercentBusy        = getLong(ATTR_CURRENT_PCT_BUSY);
346    averagePercentBusy        = getLong(ATTR_AVERAGE_PCT_BUSY);
347    recentPercentBusy         = getLong(ATTR_RECENT_PCT_BUSY);
348    maxPercentBusy            = getLong(ATTR_MAX_PCT_BUSY);
349    averageQueueTimeMillis    = getLong(ATTR_AVERAGE_QUEUE_TIME_MILLIS);
350    recentQueueTimeMillis     = getLong(ATTR_RECENT_QUEUE_TIME_MILLIS);
351    currentAdminSize          = getLong(ATTR_CURRENT_ADMIN_QUEUE_SIZE);
352    maxAdminSize              = getLong(ATTR_MAX_ADMIN_SESSION_QUEUE_SIZE);
353    numAdminWorkerThreads     = getLong(ATTR_NUM_ADMIN_WORKER_THREADS);
354    numBusyAdminWorkerThreads = getLong(ATTR_NUM_BUSY_ADMIN_WORKER_THREADS);
355  }
356
357
358
359  /**
360   * Retrieves the average number of operations observed in the work queue.
361   *
362   * @return  The average number of operations observed in the work queue, or
363   *          {@code null} if that information was not included in the monitor
364   *          entry.
365   */
366  @Nullable()
367  public Long getAverageSize()
368  {
369    return averageSize;
370  }
371
372
373
374  /**
375   * Retrieves the average number of operations observed in the work queue over
376   * a recent interval.
377   *
378   * @return  The average number of operations observed in the work queue over a
379   *          recent interval, or {@code null} if that information was not
380   *          included in the monitor entry.
381   */
382  @Nullable()
383  public Long getRecentAverageSize()
384  {
385    return recentAverageSize;
386  }
387
388
389
390  /**
391   * Retrieves the number of operations that are currently in the work queue
392   * waiting to be processed.
393   *
394   * @return  The number of operations that are currently in the work queue
395   *          waiting to be processed, or {@code null} if that information was
396   *          not included in the monitor entry.
397   */
398  @Nullable()
399  public Long getCurrentSize()
400  {
401    return currentSize;
402  }
403
404
405
406  /**
407   * Retrieves the maximum number of operations observed in the work queue at
408   * any given time.
409   *
410   * @return  The total number of operations observed in the work queue at any
411   *          given time, or {@code null} if that information was not included
412   *          in the monitor entry.
413   */
414  @Nullable()
415  public Long getMaxSize()
416  {
417    return maxSize;
418  }
419
420
421
422  /**
423   * Retrieves the total number of operation requests that were rejected because
424   * the work queue was at its maximum capacity.
425   *
426   * @return  The total number of operation requests rejected because the work
427   *          queue was at its maximum capacity, or {@code null} if that
428   *          information was not included in the monitor entry.
429   */
430  @Nullable()
431  public Long getRequestsRejectedDueToQueueFull()
432  {
433    return requestsRejected;
434  }
435
436
437
438  /**
439   * Retrieves the total number of operation requests that have been stolen from
440   * their primary queue by a worker thread associated with a different queue.
441   *
442   * @return  The total number of operation requests that have been stolen from
443   *          their primary queue by a worker thread associated with a different
444   *          queue, or {@code null} if that information was not included in the
445   *          monitor entry.
446   */
447  @Nullable()
448  public Long getRequestsStolen()
449  {
450    return requestsStolen;
451  }
452
453
454
455  /**
456   * Retrieves the number of worker threads configured for the work queue.
457   *
458   * @return  The number of worker threads configured for the work queue, or
459   *          {@code null} if that information was not included in the monitor
460   *          entry.
461   */
462  @Nullable()
463  public Long getNumWorkerThreads()
464  {
465    return numWorkerThreads;
466  }
467
468
469
470  /**
471   * Retrieves the number of worker threads that are currently busy processing
472   * an operation.
473   *
474   * @return  The number of worker threads that are currently busy processing an
475   *          operation, or {@code null} if that information was not included in
476   *          the monitor entry.
477   */
478  @Nullable()
479  public Long getNumBusyWorkerThreads()
480  {
481    return numBusyWorkerThreads;
482  }
483
484
485
486  /**
487   * Retrieves the percentage of worker threads that are currently busy
488   * processing an operation.
489   *
490   * @return  The percentage of worker threads that are currently busy
491   *          processing an operation, or {@code null} if that information was
492   *          not included in the monitor entry.
493   */
494  @Nullable()
495  public Long getCurrentWorkerThreadPercentBusy()
496  {
497    return currentPercentBusy;
498  }
499
500
501
502  /**
503   * Retrieves the average percentage of the time since startup that worker
504   * threads have spent busy processing operations.
505   *
506   * @return  The average percentage of the time since startup that worker
507   *          threads have spent busy processing operations, or {@code null} if
508   *          that information was not included in the monitor entry.
509   */
510  @Nullable()
511  public Long getAverageWorkerThreadPercentBusy()
512  {
513    return averagePercentBusy;
514  }
515
516
517
518  /**
519   * Retrieves the percentage of the time over a recent interval that worker
520   * threads have spent busy processing operations.
521   *
522   * @return  The percentage of the time over a recent interval that worker
523   *          threads have spent busy processing operations, or {@code null} if
524   *          that information was not included in the monitor entry.
525   */
526  @Nullable()
527  public Long getRecentWorkerThreadPercentBusy()
528  {
529    return recentPercentBusy;
530  }
531
532
533
534  /**
535   * Retrieves the maximum percentage of the time over any interval that worker
536   * threads have spent busy processing operations.
537   *
538   * @return  The maximum percentage of the time over any interval that worker
539   *          threads have spent busy processing operations, or {@code null} if
540   *          that information was not included in the monitor entry.
541   */
542  @Nullable()
543  public Long getMaxWorkerThreadPercentBusy()
544  {
545    return maxPercentBusy;
546  }
547
548
549
550  /**
551   * Retrieves the average length of time in milliseconds that operations have
552   * been required to wait on the work queue before being picked up by a worker
553   * thread.
554   *
555   * @return  The average length of time in milliseconds that operations have
556   *          been required to wait on the work queue, or {@code null} if that
557   *          information was not included in the monitor entry.
558   */
559  @Nullable()
560  public Long getAverageOperationQueueTimeMillis()
561  {
562    return averageQueueTimeMillis;
563  }
564
565
566
567  /**
568   * Retrieves the average length of time in milliseconds that
569   * recently-processed operations have been required to wait on the work queue
570   * before being picked up by a worker thread.
571   *
572   * @return  The average length of time in milliseconds that recently-processed
573   *          operations have been required to wait on the work queue, or
574   *          {@code null} if that information was not included in the monitor
575   *          entry.
576   */
577  @Nullable()
578  public Long getRecentOperationQueueTimeMillis()
579  {
580    return recentQueueTimeMillis;
581  }
582
583
584
585  /**
586   * Retrieves the number of operations that are currently waiting to be
587   * processed in the portion of the work queue reserved for operations that are
588   * part of an administrative session.
589   *
590   * @return  The number of operations that are currently waiting to be
591   *          processed in the portion of the work queue reserved for operations
592   *          that are part of an administrative session, or {@code null} if
593   *          that information was not included in the monitor entry.
594   */
595  @Nullable()
596  public Long getCurrentAdministrativeSessionQueueSize()
597  {
598    return currentAdminSize;
599  }
600
601
602
603  /**
604   * Retrieves the maximum number of operations observed in the dedicated
605   * administrative session queue at any given time.
606   *
607   * @return  The total number of operations observed in the dedicated
608   *          administrative session queue at any given time, or {@code null} if
609   *          that information was not included in the monitor entry.
610   */
611  @Nullable()
612  public Long getMaxAdministrativeSessionQueueSize()
613  {
614    return maxAdminSize;
615  }
616
617
618
619  /**
620   * Retrieves the number of worker threads that have been reserved for
621   * processing operations that are part of an administrative session.
622   *
623   * @return  The number of worker threads that have been reserved for
624   *          processing operations that are part of an administrative session,
625   *          or {@code null} if that information was not included in the
626   *          monitor entry.
627   */
628  @Nullable()
629  public Long getNumAdministrativeSessionWorkerThreads()
630  {
631    return numAdminWorkerThreads;
632  }
633
634
635
636  /**
637   * Retrieves the number of worker threads that are currently busy processing
638   * an operation which is part of an administrative session.
639   *
640   * @return  The number of worker threads that are currently busy processing an
641   *          operation which is part of an administrative session, or
642   *          {@code null} if that information was not included in the monitor
643   *          entry.
644   */
645  @Nullable()
646  public Long getNumBusyAdministrativeSessionWorkerThreads()
647  {
648    return numBusyAdminWorkerThreads;
649  }
650
651
652
653  /**
654   * {@inheritDoc}
655   */
656  @Override()
657  @NotNull()
658  public String getMonitorDisplayName()
659  {
660    return INFO_UNBOUNDID_WORK_QUEUE_MONITOR_DISPNAME.get();
661  }
662
663
664
665  /**
666   * {@inheritDoc}
667   */
668  @Override()
669  @NotNull()
670  public String getMonitorDescription()
671  {
672    return INFO_UNBOUNDID_WORK_QUEUE_MONITOR_DESC.get();
673  }
674
675
676
677  /**
678   * {@inheritDoc}
679   */
680  @Override()
681  @NotNull()
682  public Map<String,MonitorAttribute> getMonitorAttributes()
683  {
684    final LinkedHashMap<String,MonitorAttribute> attrs =
685         new LinkedHashMap<>(StaticUtils.computeMapCapacity(50));
686
687    if (requestsRejected != null)
688    {
689      addMonitorAttribute(attrs,
690           ATTR_REQUESTS_REJECTED,
691           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_REQUESTS_REJECTED.get(),
692           INFO_UNBOUNDID_WORK_QUEUE_DESC_REQUESTS_REJECTED.get(),
693           requestsRejected);
694    }
695
696    if (requestsStolen != null)
697    {
698      addMonitorAttribute(attrs,
699           ATTR_REQUESTS_STOLEN,
700           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_REQUESTS_STOLEN.get(),
701           INFO_UNBOUNDID_WORK_QUEUE_DESC_REQUESTS_STOLEN.get(),
702           requestsStolen);
703    }
704
705    if (currentSize != null)
706    {
707      addMonitorAttribute(attrs,
708           ATTR_CURRENT_SIZE,
709           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_CURRENT_SIZE.get(),
710           INFO_UNBOUNDID_WORK_QUEUE_DESC_CURRENT_SIZE.get(),
711           currentSize);
712    }
713
714    if (recentAverageSize != null)
715    {
716      addMonitorAttribute(attrs,
717           ATTR_RECENT_AVERAGE_SIZE,
718           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_RECENT_AVERAGE_SIZE.get(),
719           INFO_UNBOUNDID_WORK_QUEUE_DESC_RECENT_AVERAGE_SIZE.get(),
720           recentAverageSize);
721    }
722
723    if (averageSize != null)
724    {
725      addMonitorAttribute(attrs,
726           ATTR_AVERAGE_SIZE,
727           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_AVERAGE_SIZE.get(),
728           INFO_UNBOUNDID_WORK_QUEUE_DESC_AVERAGE_SIZE.get(),
729           averageSize);
730    }
731
732    if (maxSize != null)
733    {
734      addMonitorAttribute(attrs,
735           ATTR_MAX_SIZE,
736           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_MAX_SIZE.get(),
737           INFO_UNBOUNDID_WORK_QUEUE_DESC_MAX_SIZE.get(),
738           maxSize);
739    }
740
741    if (numWorkerThreads != null)
742    {
743      addMonitorAttribute(attrs,
744           ATTR_NUM_WORKER_THREADS,
745           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_NUM_THREADS.get(),
746           INFO_UNBOUNDID_WORK_QUEUE_DESC_NUM_THREADS.get(),
747           numWorkerThreads);
748    }
749
750    if (numBusyWorkerThreads != null)
751    {
752      addMonitorAttribute(attrs,
753           ATTR_NUM_BUSY_WORKER_THREADS,
754           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_NUM_BUSY_THREADS.get(),
755           INFO_UNBOUNDID_WORK_QUEUE_DESC_NUM_BUSY_THREADS.get(),
756           numBusyWorkerThreads);
757    }
758
759    if (currentPercentBusy != null)
760    {
761      addMonitorAttribute(attrs,
762           ATTR_CURRENT_PCT_BUSY,
763           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_CURRENT_PCT_BUSY.get(),
764           INFO_UNBOUNDID_WORK_QUEUE_DESC_CURRENT_PCT_BUSY.get(),
765           currentPercentBusy);
766    }
767
768    if (averagePercentBusy != null)
769    {
770      addMonitorAttribute(attrs,
771           ATTR_AVERAGE_PCT_BUSY,
772           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_AVG_PCT_BUSY.get(),
773           INFO_UNBOUNDID_WORK_QUEUE_DESC_AVG_PCT_BUSY.get(),
774           averagePercentBusy);
775    }
776
777    if (recentPercentBusy != null)
778    {
779      addMonitorAttribute(attrs,
780           ATTR_RECENT_PCT_BUSY,
781           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_RECENT_PCT_BUSY.get(),
782           INFO_UNBOUNDID_WORK_QUEUE_DESC_RECENT_PCT_BUSY.get(),
783           recentPercentBusy);
784    }
785
786    if (maxPercentBusy != null)
787    {
788      addMonitorAttribute(attrs,
789           ATTR_MAX_PCT_BUSY,
790           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_MAX_PCT_BUSY.get(),
791           INFO_UNBOUNDID_WORK_QUEUE_DESC_MAX_PCT_BUSY.get(),
792           maxPercentBusy);
793    }
794
795    if (averageQueueTimeMillis != null)
796    {
797      addMonitorAttribute(attrs,
798           ATTR_AVERAGE_QUEUE_TIME_MILLIS,
799           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_AVG_QUEUE_TIME.get(),
800           INFO_UNBOUNDID_WORK_QUEUE_DESC_AVG_QUEUE_TIME.get(),
801           averageQueueTimeMillis);
802    }
803
804    if (recentQueueTimeMillis != null)
805    {
806      addMonitorAttribute(attrs,
807           ATTR_RECENT_QUEUE_TIME_MILLIS,
808           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_RECENT_QUEUE_TIME.get(),
809           INFO_UNBOUNDID_WORK_QUEUE_DESC_RECENT_QUEUE_TIME.get(),
810           recentQueueTimeMillis);
811    }
812
813    if (currentAdminSize != null)
814    {
815      addMonitorAttribute(attrs,
816           ATTR_CURRENT_ADMIN_QUEUE_SIZE,
817           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_CURRENT_ADMIN_QUEUE_SIZE.get(),
818           INFO_UNBOUNDID_WORK_QUEUE_DESC_CURRENT_ADMIN_QUEUE_SIZE.get(),
819           currentAdminSize);
820    }
821
822    if (maxAdminSize != null)
823    {
824      addMonitorAttribute(attrs,
825           ATTR_MAX_ADMIN_SESSION_QUEUE_SIZE,
826           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_MAX_ADMIN_QUEUE_SIZE.get(),
827           INFO_UNBOUNDID_WORK_QUEUE_DESC_MAX_ADMIN_QUEUE_SIZE.get(),
828           maxAdminSize);
829    }
830
831    if (numAdminWorkerThreads != null)
832    {
833      addMonitorAttribute(attrs,
834           ATTR_NUM_ADMIN_WORKER_THREADS,
835           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_NUM_ADMIN_THREADS.get(),
836           INFO_UNBOUNDID_WORK_QUEUE_DESC_NUM_ADMIN_THREADS.get(),
837           numAdminWorkerThreads);
838    }
839
840    if (numBusyAdminWorkerThreads != null)
841    {
842      addMonitorAttribute(attrs,
843           ATTR_NUM_BUSY_ADMIN_WORKER_THREADS,
844           INFO_UNBOUNDID_WORK_QUEUE_DISPNAME_NUM_BUSY_ADMIN_THREADS.get(),
845           INFO_UNBOUNDID_WORK_QUEUE_DESC_NUM_BUSY_ADMIN_THREADS.get(),
846           numBusyAdminWorkerThreads);
847    }
848
849    return Collections.unmodifiableMap(attrs);
850  }
851}