001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.protocols.ldap;
028    
029    
030    
031    import java.util.ArrayList;
032    import java.util.LinkedHashSet;
033    
034    import org.opends.messages.Message;
035    import org.opends.server.admin.std.server.MonitorProviderCfg;
036    import org.opends.server.api.MonitorProvider;
037    import org.opends.server.core.DirectoryServer;
038    import org.opends.server.config.ConfigException;
039    import org.opends.server.loggers.debug.DebugTracer;
040    import org.opends.server.protocols.asn1.ASN1OctetString;
041    import org.opends.server.types.Attribute;
042    import org.opends.server.types.AttributeType;
043    import org.opends.server.types.AttributeValue;
044    import org.opends.server.types.DebugLogLevel;
045    
046    import static org.opends.messages.ProtocolMessages.*;
047    import static org.opends.server.loggers.debug.DebugLogger.*;
048    import static org.opends.server.protocols.ldap.LDAPConstants.*;
049    
050    
051    
052    /**
053     * This class defines a data structure that will be used to keep track of
054     * various metrics related to LDAP communication that the server has conducted.
055     * The statistics that will be tracked include:
056     *
057     * <UL>
058     *   <LI>The total number of LDAP client connections accepted by the
059     *       server.</LI>
060     *   <LI>The total number of LDAP client connections that have been closed.</LI>
061     *   <LI>The total number of LDAP messages read, both overall and broken down
062     *       by message type.</LI>
063     *   <LI>The total number of LDAP messages written, both overall and broken down
064     *       by message type.</LI>
065     *   <LI>The total number of bytes read from LDAP clients.</LI>
066     *   <LI>The total number of bytes written to LDAP clients.</LI>
067     * </UL>
068     *
069     * <BR><BR>
070     * This class may also be used in a hierarchical form if it is desirable to
071     * get specific and general statistics at the same time (e.g., information
072     * about the interaction with a specific client or aggregated for all clients).
073     */
074    public class LDAPStatistics
075           extends MonitorProvider<MonitorProviderCfg>
076    {
077      /**
078       * The tracer object for the debug logger.
079       */
080      private static final DebugTracer TRACER = getTracer();
081    
082    
083    
084      // The statistics maintained by this class.
085      private long abandonRequests;
086      private long addRequests;
087      private long addResponses;
088      private long bindRequests;
089      private long bindResponses;
090      private long bytesRead;
091      private long bytesWritten;
092      private long compareRequests;
093      private long compareResponses;
094      private long connectionsClosed;
095      private long connectionsEstablished;
096      private long deleteRequests;
097      private long deleteResponses;
098      private long extendedRequests;
099      private long extendedResponses;
100      private long messagesRead;
101      private long messagesWritten;
102      private long modifyRequests;
103      private long modifyResponses;
104      private long modifyDNRequests;
105      private long modifyDNResponses;
106      private long operationsAbandoned;
107      private long operationsCompleted;
108      private long operationsInitiated;
109      private long searchRequests;
110      private long searchResultEntries;
111      private long searchResultReferences;
112      private long searchResultsDone;
113      private long unbindRequests;
114    
115      // The parent that should also be updated whenever statistics in this object
116      // are updated.
117      private LDAPStatistics parent;
118    
119      // The locks used to provide threadsafe access to this class.  In this case,
120      // read and write refer to the type of LDAP communication, not access to the
121      // protected data.
122      private Object abandonLock;
123      private Object connectLock;
124      private Object disconnectLock;
125      private Object readLock;
126      private Object writeLock;
127    
128      // The instance name for this monitor provider instance.
129      private String instanceName;
130    
131    
132    
133    
134      /**
135       * Creates a new instance of this class with no parent.
136       *
137       * @param  instanceName  The name for this monitor provider instance.
138       */
139      public LDAPStatistics(String instanceName)
140      {
141        this(instanceName, null);
142    
143        DirectoryServer.registerMonitorProvider(this);
144      }
145    
146    
147    
148      /**
149       * Creates a new instance of this class with the specified parent.
150       *
151       * @param  instanceName  The name for this monitor provider instance.
152       * @param  parent        The parent object that should also be updated
153       *                       whenever this class is updated.  It may be null if
154       *                       there should not be a parent.
155       */
156      public LDAPStatistics(String instanceName, LDAPStatistics parent)
157      {
158        super("LDAP Statistics Monitor Provider");
159    
160    
161        this.instanceName = instanceName;
162        this.parent       = parent;
163    
164        abandonLock    = new Object();
165        connectLock    = new Object();
166        disconnectLock = new Object();
167        readLock       = new Object();
168        writeLock      = new Object();
169    
170        abandonRequests        = 0;
171        addRequests            = 0;
172        addResponses           = 0;
173        bindRequests           = 0;
174        bindResponses          = 0;
175        bytesRead              = 0;
176        bytesWritten           = 0;
177        compareRequests        = 0;
178        compareResponses       = 0;
179        connectionsClosed      = 0;
180        connectionsEstablished = 0;
181        deleteRequests         = 0;
182        deleteResponses        = 0;
183        extendedRequests       = 0;
184        extendedResponses      = 0;
185        messagesRead           = 0;
186        messagesWritten        = 0;
187        modifyRequests         = 0;
188        modifyResponses        = 0;
189        modifyDNRequests       = 0;
190        modifyDNResponses      = 0;
191        operationsAbandoned    = 0;
192        operationsCompleted    = 0;
193        operationsInitiated    = 0;
194        searchRequests         = 0;
195        searchResultEntries    = 0;
196        searchResultReferences = 0;
197        searchResultsDone      = 0;
198        unbindRequests         = 0;
199      }
200    
201    
202    
203      /**
204       * {@inheritDoc}
205       */
206      public void initializeMonitorProvider(MonitorProviderCfg configuration)
207             throws ConfigException
208      {
209        // Throw an exception, because this monitor is not intended to be
210        // dynamically loaded from the configuration.  Rather, it should be
211        // explicitly created and registered by the LDAP connection handler or an
212        // LDAP client connection.
213        Message message = ERR_LDAP_STATS_INVALID_MONITOR_INITIALIZATION.get(
214            String.valueOf(configuration.dn()));
215        throw new ConfigException(message);
216      }
217    
218    
219    
220      /**
221       * Retrieves the name of this monitor provider.  It should be unique among all
222       * monitor providers, including all instances of the same monitor provider.
223       *
224       * @return  The name of this monitor provider.
225       */
226      public String getMonitorInstanceName()
227      {
228        return instanceName;
229      }
230    
231    
232    
233      /**
234       * Retrieves the length of time in milliseconds that should elapse between
235       * calls to the <CODE>updateMonitorData()</CODE> method.  A negative or zero
236       * return value indicates that the <CODE>updateMonitorData()</CODE> method
237       * should not be periodically invoked.
238       *
239       * @return  The length of time in milliseconds that should elapse between
240       *          calls to the <CODE>updateMonitorData()</CODE> method.
241       */
242      public long getUpdateInterval()
243      {
244        // This monitor should not run periodically.
245        return -1;
246      }
247    
248    
249    
250      /**
251       * Performs any processing periodic processing that may be desired to update
252       * the information associated with this monitor.  Note that best-effort
253       * attempts will be made to ensure that calls to this method come
254       * <CODE>getUpdateInterval()</CODE> milliseconds apart, but no guarantees will
255       * be made.
256       */
257      public void updateMonitorData()
258      {
259        // No implementation is required since this does not do periodic updates.
260      }
261    
262    
263    
264      /**
265       * Retrieves a set of attributes containing monitor data that should be
266       * returned to the client if the corresponding monitor entry is requested.
267       *
268       * @return  A set of attributes containing monitor data that should be
269       *          returned to the client if the corresponding monitor entry is
270       *          requested.
271       */
272      public ArrayList<Attribute> getMonitorData()
273      {
274        ArrayList<Attribute> attrs = new ArrayList<Attribute>(29);
275    
276        long tmpAbandonRequests;
277        long tmpAddRequests;
278        long tmpAddResponses;
279        long tmpBindRequests;
280        long tmpBindResponses;
281        long tmpBytesRead;
282        long tmpBytesWritten;
283        long tmpCompareRequests;
284        long tmpCompareResponses;
285        long tmpConnectionsClosed;
286        long tmpConnectionsEstablished;
287        long tmpDeleteRequests;
288        long tmpDeleteResponses;
289        long tmpExtendedRequests;
290        long tmpExtendedResponses;
291        long tmpMessagesRead;
292        long tmpMessagesWritten;
293        long tmpModifyRequests;
294        long tmpModifyResponses;
295        long tmpModifyDNRequests;
296        long tmpModifyDNResponses;
297        long tmpOperationsAbandoned;
298        long tmpOperationsCompleted;
299        long tmpOperationsInitiated;
300        long tmpSearchRequests;
301        long tmpSearchEntries;
302        long tmpSearchReferences;
303        long tmpSearchResultsDone;
304        long tmpUnbindRequests;
305    
306        // Quickly grab the locks and store consistent copies of the information.
307        // Note that when grabbing multiple locks, it is essential that they are all
308        // acquired in the same order to prevent deadlocks.
309        synchronized (abandonLock)
310        {
311          synchronized (connectLock)
312          {
313            synchronized (disconnectLock)
314            {
315              synchronized (writeLock)
316              {
317                synchronized (readLock)
318                {
319                  tmpAbandonRequests        = abandonRequests;
320                  tmpAddRequests            = addRequests;
321                  tmpAddResponses           = addResponses;
322                  tmpBindRequests           = bindRequests;
323                  tmpBindResponses          = bindResponses;
324                  tmpBytesRead              = bytesRead;
325                  tmpBytesWritten           = bytesWritten;
326                  tmpCompareRequests        = compareRequests;
327                  tmpCompareResponses       = compareResponses;
328                  tmpConnectionsClosed      = connectionsClosed;
329                  tmpConnectionsEstablished = connectionsEstablished;
330                  tmpDeleteRequests         = deleteRequests;
331                  tmpDeleteResponses        = deleteResponses;
332                  tmpExtendedRequests       = extendedRequests;
333                  tmpExtendedResponses      = extendedResponses;
334                  tmpMessagesRead           = messagesRead;
335                  tmpMessagesWritten        = messagesWritten;
336                  tmpModifyRequests         = modifyRequests;
337                  tmpModifyResponses        = modifyResponses;
338                  tmpModifyDNRequests       = modifyDNRequests;
339                  tmpModifyDNResponses      = modifyDNResponses;
340                  tmpOperationsAbandoned    = operationsAbandoned;
341                  tmpOperationsCompleted    = operationsCompleted;
342                  tmpOperationsInitiated    = operationsInitiated;
343                  tmpSearchRequests         = searchRequests;
344                  tmpSearchEntries          = searchResultEntries;
345                  tmpSearchReferences       = searchResultReferences;
346                  tmpSearchResultsDone      = searchResultsDone;
347                  tmpUnbindRequests         = unbindRequests;
348                }
349              }
350            }
351          }
352        }
353    
354    
355        // Construct the list of attributes to return.
356        attrs.add(createAttribute("connectionsEstablished",
357                                  String.valueOf(tmpConnectionsEstablished)));
358        attrs.add(createAttribute("connectionsClosed",
359                                  String.valueOf(tmpConnectionsClosed)));
360        attrs.add(createAttribute("bytesRead", String.valueOf(tmpBytesRead)));
361        attrs.add(createAttribute("bytesWritten", String.valueOf(tmpBytesWritten)));
362        attrs.add(createAttribute("ldapMessagesRead",
363                                  String.valueOf(tmpMessagesRead)));
364        attrs.add(createAttribute("ldapMessagesWritten",
365                                  String.valueOf(tmpMessagesWritten)));
366        attrs.add(createAttribute("operationsAbandoned",
367                                  String.valueOf(tmpOperationsAbandoned)));
368        attrs.add(createAttribute("operationsInitiated",
369                                  String.valueOf(tmpOperationsInitiated)));
370        attrs.add(createAttribute("operationsCompleted",
371                                  String.valueOf(tmpOperationsCompleted)));
372        attrs.add(createAttribute("abandonRequests",
373                                  String.valueOf(tmpAbandonRequests)));
374        attrs.add(createAttribute("addRequests", String.valueOf(tmpAddRequests)));
375        attrs.add(createAttribute("addResponses", String.valueOf(tmpAddResponses)));
376        attrs.add(createAttribute("bindRequests", String.valueOf(tmpBindRequests)));
377        attrs.add(createAttribute("bindResponses",
378                                  String.valueOf(tmpBindResponses)));
379        attrs.add(createAttribute("compareRequests",
380                                  String.valueOf(tmpCompareRequests)));
381        attrs.add(createAttribute("compareResponses",
382                                  String.valueOf(tmpCompareResponses)));
383        attrs.add(createAttribute("deleteRequests",
384                                  String.valueOf(tmpDeleteRequests)));
385        attrs.add(createAttribute("deleteResponses",
386                                  String.valueOf(tmpDeleteResponses)));
387        attrs.add(createAttribute("extendedRequests",
388                                  String.valueOf(tmpExtendedRequests)));
389        attrs.add(createAttribute("extendedResponses",
390                                  String.valueOf(tmpExtendedResponses)));
391        attrs.add(createAttribute("modifyRequests",
392                                  String.valueOf(tmpModifyRequests)));
393        attrs.add(createAttribute("modifyResponses",
394                                  String.valueOf(tmpModifyResponses)));
395        attrs.add(createAttribute("modifyDNRequests",
396                                  String.valueOf(tmpModifyDNRequests)));
397        attrs.add(createAttribute("modifyDNResponses",
398                                  String.valueOf(tmpModifyDNResponses)));
399        attrs.add(createAttribute("searchRequests",
400                                  String.valueOf(tmpSearchRequests)));
401        attrs.add(createAttribute("searchResultEntries",
402                                  String.valueOf(tmpSearchEntries)));
403        attrs.add(createAttribute("searchResultReferences",
404                                  String.valueOf(tmpSearchReferences)));
405        attrs.add(createAttribute("searchResultsDone",
406                                  String.valueOf(tmpSearchResultsDone)));
407        attrs.add(createAttribute("unbindRequests",
408                                  String.valueOf(tmpUnbindRequests)));
409    
410        return attrs;
411      }
412    
413    
414    
415      /**
416       * Clears any statistical information collected to this point.
417       */
418      public void clearStatistics()
419      {
420        // Quickly grab the locks and store consistent copies of the information.
421        // Note that when grabbing multiple locks, it is essential that they are all
422        // acquired in the same order to prevent deadlocks.
423        synchronized (abandonLock)
424        {
425          synchronized (connectLock)
426          {
427            synchronized (disconnectLock)
428            {
429              synchronized (writeLock)
430              {
431                synchronized (readLock)
432                {
433                  abandonRequests        = 0;
434                  addRequests            = 0;
435                  addResponses           = 0;
436                  bindRequests           = 0;
437                  bindResponses          = 0;
438                  bytesRead              = 0;
439                  bytesWritten           = 0;
440                  compareRequests        = 0;
441                  compareResponses       = 0;
442                  connectionsClosed      = 0;
443                  connectionsEstablished = 0;
444                  deleteRequests         = 0;
445                  deleteResponses        = 0;
446                  extendedRequests       = 0;
447                  extendedResponses      = 0;
448                  messagesRead           = 0;
449                  messagesWritten        = 0;
450                  modifyRequests         = 0;
451                  modifyResponses        = 0;
452                  modifyDNRequests       = 0;
453                  modifyDNResponses      = 0;
454                  operationsAbandoned    = 0;
455                  operationsCompleted    = 0;
456                  operationsInitiated    = 0;
457                  searchRequests         = 0;
458                  searchResultEntries    = 0;
459                  searchResultReferences = 0;
460                  searchResultsDone      = 0;
461                  unbindRequests         = 0;
462                }
463              }
464            }
465          }
466        }
467      }
468    
469    
470    
471      /**
472       * Updates the appropriate set of counters to indicate that a new connection
473       * has been established.
474       */
475      public void updateConnect()
476      {
477        synchronized (connectLock)
478        {
479          connectionsEstablished++;
480        }
481    
482        // Update the parent if there is one.
483        if (parent != null)
484        {
485          parent.updateConnect();
486        }
487      }
488    
489    
490    
491      /**
492       * Updates the appropriate set of counters to indicate that a connection has
493       * been closed.
494       */
495      public void updateDisconnect()
496      {
497        synchronized (disconnectLock)
498        {
499          connectionsClosed++;
500        }
501    
502        // Update the parent if there is one.
503        if (parent != null)
504        {
505          parent.updateDisconnect();
506        }
507      }
508    
509    
510    
511      /**
512       * Updates the appropriate set of counters to indicate that the specified
513       * number of bytes have been read by the client.
514       *
515       * @param  bytesRead  The number of bytes read by the client.
516       */
517      public void updateBytesRead(int bytesRead)
518      {
519        synchronized (readLock)
520        {
521          this.bytesRead += bytesRead;
522        }
523    
524        // Update the parent if there is one.
525        if (parent != null)
526        {
527          parent.updateBytesRead(bytesRead);
528        }
529      }
530    
531    
532    
533      /**
534       * Updates the appropriate set of counters based on the provided message that
535       * has been read from the client.
536       *
537       * @param  message  The message that was read from the client.
538       */
539      public void updateMessageRead(LDAPMessage message)
540      {
541        synchronized (readLock)
542        {
543          messagesRead++;
544          operationsInitiated++;
545    
546          switch (message.getProtocolOp().getType())
547          {
548            case OP_TYPE_ABANDON_REQUEST:
549              abandonRequests++;
550              break;
551            case OP_TYPE_ADD_REQUEST:
552              addRequests++;
553              break;
554            case OP_TYPE_BIND_REQUEST:
555              bindRequests++;
556              break;
557            case OP_TYPE_COMPARE_REQUEST:
558              compareRequests++;
559              break;
560            case OP_TYPE_DELETE_REQUEST:
561              deleteRequests++;
562              break;
563            case OP_TYPE_EXTENDED_REQUEST:
564              extendedRequests++;
565              break;
566            case OP_TYPE_MODIFY_REQUEST:
567              modifyRequests++;
568              break;
569            case OP_TYPE_MODIFY_DN_REQUEST:
570              modifyDNRequests++;
571              break;
572            case OP_TYPE_SEARCH_REQUEST:
573              searchRequests++;
574              break;
575            case OP_TYPE_UNBIND_REQUEST:
576              unbindRequests++;
577              break;
578          }
579        }
580    
581        // Update the parent if there is one.
582        if (parent != null)
583        {
584          parent.updateMessageRead(message);
585        }
586      }
587    
588    
589    
590      /**
591       * Updates the appropriate set of counters based on the provided message that
592       * has been written to the client.
593       *
594       * @param  message       The message that was written to the client.
595       * @param  bytesWritten  The size of the message written in bytes.
596       */
597      public void updateMessageWritten(LDAPMessage message, int bytesWritten)
598      {
599        synchronized (writeLock)
600        {
601          this.bytesWritten += bytesWritten;
602          messagesWritten++;
603    
604          switch (message.getProtocolOp().getType())
605          {
606            case OP_TYPE_ADD_RESPONSE:
607              addResponses++;
608              operationsCompleted++;
609              break;
610            case OP_TYPE_BIND_RESPONSE:
611              bindResponses++;
612              operationsCompleted++;
613              break;
614            case OP_TYPE_COMPARE_RESPONSE:
615              compareResponses++;
616              operationsCompleted++;
617              break;
618            case OP_TYPE_DELETE_RESPONSE:
619              deleteResponses++;
620              operationsCompleted++;
621              break;
622            case OP_TYPE_EXTENDED_RESPONSE:
623              extendedResponses++;
624    
625              // We don't want to include unsolicited notifications as "completed"
626              // operations.
627              if (message.getMessageID() > 0)
628              {
629                operationsCompleted++;
630              }
631              break;
632            case OP_TYPE_MODIFY_RESPONSE:
633              modifyResponses++;
634              operationsCompleted++;
635              break;
636            case OP_TYPE_MODIFY_DN_RESPONSE:
637              modifyDNResponses++;
638              operationsCompleted++;
639              break;
640            case OP_TYPE_SEARCH_RESULT_ENTRY:
641              searchResultEntries++;
642              break;
643            case OP_TYPE_SEARCH_RESULT_REFERENCE:
644              searchResultReferences++;
645              break;
646            case OP_TYPE_SEARCH_RESULT_DONE:
647              searchResultsDone++;
648              operationsCompleted++;
649              break;
650          }
651        }
652    
653        // Update the parent if there is one.
654        if (parent != null)
655        {
656          parent.updateMessageWritten(message, bytesWritten);
657        }
658      }
659    
660    
661    
662      /**
663       * Updates the appropriate set of counters to indicate that an operation was
664       * abandoned without sending a response to the client.
665       */
666      public void updateAbandonedOperation()
667      {
668        synchronized (abandonLock)
669        {
670          operationsAbandoned++;
671        }
672    
673        // Update the parent if there is one.
674        if (parent != null)
675        {
676          parent.updateAbandonedOperation();
677        }
678      }
679    
680    
681    
682      /**
683       * Constructs an attribute using the provided information.  It will have the
684       * default syntax.
685       *
686       * @param  name   The name to use for the attribute.
687       * @param  value  The value to use for the attribute.
688       *
689       * @return  the constructed attribute.
690       */
691      private Attribute createAttribute(String name, String value)
692      {
693        AttributeType attrType = DirectoryServer.getDefaultAttributeType(name);
694    
695        ASN1OctetString encodedValue = new ASN1OctetString(value);
696        LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
697    
698        try
699        {
700          values.add(new AttributeValue(encodedValue,
701                                        attrType.normalize(encodedValue)));
702        }
703        catch (Exception e)
704        {
705          if (debugEnabled())
706          {
707            TRACER.debugCaught(DebugLogLevel.ERROR, e);
708          }
709    
710          values.add(new AttributeValue(encodedValue, encodedValue));
711        }
712    
713        return new Attribute(attrType, name, values);
714      }
715    
716    
717    
718      /**
719       * Retrieves the number of client connections that have been established.
720       *
721       * @return  The number of client connections that have been established.
722       */
723      public long getConnectionsEstablished()
724      {
725        synchronized (connectLock)
726        {
727          return connectionsEstablished;
728        }
729      }
730    
731    
732    
733      /**
734       * Retrieves the number of client connections that have been closed.
735       *
736       * @return  The number of client connections that have been closed.
737       */
738      public long getConnectionsClosed()
739      {
740        synchronized (disconnectLock)
741        {
742          return connectionsClosed;
743        }
744      }
745    
746    
747    
748      /**
749       * Retrieves the number of bytes that have been received from clients.
750       *
751       * @return  The number of bytes that have been received from clients.
752       */
753      public long getBytesRead()
754      {
755        synchronized (readLock)
756        {
757          return bytesRead;
758        }
759      }
760    
761    
762    
763      /**
764       * Retrieves the number of bytes that have been written to clients.
765       *
766       * @return  The number of bytes that have been written to clients.
767       */
768      public long getBytesWritten()
769      {
770        synchronized (writeLock)
771        {
772          return bytesWritten;
773        }
774      }
775    
776    
777    
778      /**
779       * Retrieves the number of LDAP messages that have been received from clients.
780       *
781       * @return  The number of LDAP messages that have been received from clients.
782       */
783      public long getMessagesRead()
784      {
785        synchronized (readLock)
786        {
787          return messagesRead;
788        }
789      }
790    
791    
792    
793      /**
794       * Retrieves the number of LDAP messages that have been written to clients.
795       *
796       * @return  The number of LDAP messages that have been written to clients.
797       */
798      public long getMessagesWritten()
799      {
800        synchronized (writeLock)
801        {
802          return messagesWritten;
803        }
804      }
805    
806    
807    
808      /**
809       * Retrieves the number of operations that have been initiated by clients.
810       *
811       * @return  The number of operations that have been initiated by clients.
812       */
813      public long getOperationsInitiated()
814      {
815        synchronized (readLock)
816        {
817          return operationsInitiated;
818        }
819      }
820    
821    
822    
823      /**
824       * Retrieves the number of operations for which the server has completed
825       * processing.
826       *
827       * @return  The number of operations for which the server has completed
828       *          processing.
829       */
830      public long getOperationsCompleted()
831      {
832        synchronized (writeLock)
833        {
834          return operationsCompleted;
835        }
836      }
837    
838    
839    
840      /**
841       * Retrieves the number of operations that have been abandoned by clients.
842       *
843       * @return  The number of operations that have been abandoned by clients.
844       */
845      public long getOperationsAbandoned()
846      {
847        synchronized (abandonLock)
848        {
849          return operationsAbandoned;
850        }
851      }
852    
853    
854    
855      /**
856       * Retrieves the number of abandon requests that have been received.
857       *
858       * @return  The number of abandon requests that have been received.
859       */
860      public long getAbandonRequests()
861      {
862        synchronized (readLock)
863        {
864          return abandonRequests;
865        }
866      }
867    
868    
869    
870      /**
871       * Retrieves the number of add requests that have been received.
872       *
873       * @return  The number of add requests that have been received.
874       */
875      public long getAddRequests()
876      {
877        synchronized (readLock)
878        {
879          return addRequests;
880        }
881      }
882    
883    
884    
885      /**
886       * Retrieves the number of add responses that have been sent.
887       *
888       * @return  The number of add responses that have been sent.
889       */
890      public long getAddResponses()
891      {
892        synchronized (writeLock)
893        {
894          return addResponses;
895        }
896      }
897    
898    
899    
900      /**
901       * Retrieves the number of bind requests that have been received.
902       *
903       * @return  The number of bind requests that have been received.
904       */
905      public long getBindRequests()
906      {
907        synchronized (readLock)
908        {
909          return bindRequests;
910        }
911      }
912    
913    
914    
915      /**
916       * Retrieves the number of bind responses that have been sent.
917       *
918       * @return  The number of bind responses that have been sent.
919       */
920      public long getBindResponses()
921      {
922        synchronized (writeLock)
923        {
924          return bindResponses;
925        }
926      }
927    
928    
929    
930      /**
931       * Retrieves the number of compare requests that have been received.
932       *
933       * @return  The number of compare requests that have been received.
934       */
935      public long getCompareRequests()
936      {
937        synchronized (readLock)
938        {
939          return compareRequests;
940        }
941      }
942    
943    
944    
945      /**
946       * Retrieves the number of compare responses that have been sent.
947       *
948       * @return  The number of compare responses that have been sent.
949       */
950      public long getCompareResponses()
951      {
952        synchronized (writeLock)
953        {
954          return compareResponses;
955        }
956      }
957    
958    
959    
960      /**
961       * Retrieves the number of delete requests that have been received.
962       *
963       * @return  The number of delete requests that have been received.
964       */
965      public long getDeleteRequests()
966      {
967        synchronized (readLock)
968        {
969          return deleteRequests;
970        }
971      }
972    
973    
974    
975      /**
976       * Retrieves the number of delete responses that have been sent.
977       *
978       * @return  The number of delete responses that have been sent.
979       */
980      public long getDeleteResponses()
981      {
982        synchronized (writeLock)
983        {
984          return deleteResponses;
985        }
986      }
987    
988    
989    
990      /**
991       * Retrieves the number of extended requests that have been received.
992       *
993       * @return  The number of extended requests that have been received.
994       */
995      public long getExtendedRequests()
996      {
997        synchronized (readLock)
998        {
999          return extendedRequests;
1000        }
1001      }
1002    
1003    
1004    
1005      /**
1006       * Retrieves the number of extended responses that have been sent.
1007       *
1008       * @return  The number of extended responses that have been sent.
1009       */
1010      public long getExtendedResponses()
1011      {
1012        synchronized (writeLock)
1013        {
1014          return extendedResponses;
1015        }
1016      }
1017    
1018    
1019    
1020      /**
1021       * Retrieves the number of modify requests that have been received.
1022       *
1023       * @return  The number of modify requests that have been received.
1024       */
1025      public long getModifyRequests()
1026      {
1027        synchronized (readLock)
1028        {
1029          return modifyRequests;
1030        }
1031      }
1032    
1033    
1034    
1035      /**
1036       * Retrieves the number of modify responses that have been sent.
1037       *
1038       * @return  The number of modify responses that have been sent.
1039       */
1040      public long getModifyResponses()
1041      {
1042        synchronized (writeLock)
1043        {
1044          return modifyResponses;
1045        }
1046      }
1047    
1048    
1049    
1050      /**
1051       * Retrieves the number of modify DN requests that have been received.
1052       *
1053       * @return  The number of modify DN requests that have been received.
1054       */
1055      public long getModifyDNRequests()
1056      {
1057        synchronized (readLock)
1058        {
1059          return modifyDNRequests;
1060        }
1061      }
1062    
1063    
1064    
1065      /**
1066       * Retrieves the number of modify DN responses that have been sent.
1067       *
1068       * @return  The number of modify DN responses that have been sent.
1069       */
1070      public long getModifyDNResponses()
1071      {
1072        synchronized (writeLock)
1073        {
1074          return modifyDNResponses;
1075        }
1076      }
1077    
1078    
1079    
1080      /**
1081       * Retrieves the number of search requests that have been received.
1082       *
1083       * @return  The number of search requests that have been received.
1084       */
1085      public long getSearchRequests()
1086      {
1087        synchronized (readLock)
1088        {
1089          return searchRequests;
1090        }
1091      }
1092    
1093    
1094    
1095      /**
1096       * Retrieves the number of search result entries that have been sent.
1097       *
1098       * @return  The number of search result entries that have been sent.
1099       */
1100      public long getSearchResultEntries()
1101      {
1102        synchronized (writeLock)
1103        {
1104          return searchResultEntries;
1105        }
1106      }
1107    
1108    
1109    
1110      /**
1111       * Retrieves the number of search result references that have been sent.
1112       *
1113       * @return  The number of search result references that have been sent.
1114       */
1115      public long getSearchResultReferences()
1116      {
1117        synchronized (writeLock)
1118        {
1119          return searchResultReferences;
1120        }
1121      }
1122    
1123    
1124    
1125      /**
1126       * Retrieves the number of search result done messages that have been sent.
1127       *
1128       * @return  The number of search result done messages that have been sent.
1129       */
1130      public long getSearchResultsDone()
1131      {
1132        synchronized (writeLock)
1133        {
1134          return searchResultsDone;
1135        }
1136      }
1137    
1138    
1139    
1140      /**
1141       * Retrieves the number of unbind requests that have been received.
1142       *
1143       * @return  The number of unbind requests that have been received.
1144       */
1145      public long getUnbindRequests()
1146      {
1147        synchronized (readLock)
1148        {
1149          return unbindRequests;
1150        }
1151      }
1152    
1153    
1154    
1155      /**
1156       * Retrieves the parent statistics tracker that will also be updated whenever
1157       * this tracker is updated.
1158       *
1159       * @return  The parent statistics tracker, or {@code null} if there is none.
1160       */
1161      public LDAPStatistics getParent()
1162      {
1163        return parent;
1164      }
1165    }
1166