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