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