001    /*
002     * Copyright 2009-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2015 UnboundID Corp.
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     */
021    package com.unboundid.ldap.sdk.unboundidds.logs;
022    
023    
024    
025    import java.util.Collections;
026    import java.util.LinkedList;
027    import java.util.List;
028    import java.util.StringTokenizer;
029    
030    import com.unboundid.ldap.sdk.ResultCode;
031    import com.unboundid.util.NotMutable;
032    import com.unboundid.util.ThreadSafety;
033    import com.unboundid.util.ThreadSafetyLevel;
034    
035    
036    
037    /**
038     * <BLOCKQUOTE>
039     *   <B>NOTE:</B>  This class is part of the Commercial Edition of the UnboundID
040     *   LDAP SDK for Java.  It is not available for use in applications that
041     *   include only the Standard Edition of the LDAP SDK, and is not supported for
042     *   use in conjunction with non-UnboundID products.
043     * </BLOCKQUOTE>
044     * This class provides a data structure that holds information about a log
045     * message that may appear in the Directory Server access log about the result
046     * of a search operation processed by the Directory Server.
047     */
048    @NotMutable()
049    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
050    public final class SearchResultAccessLogMessage
051           extends SearchRequestAccessLogMessage
052           implements OperationResultAccessLogMessage
053    {
054      /**
055       * The serial version UID for this serializable class.
056       */
057      private static final long serialVersionUID = 7181644154168110011L;
058    
059    
060    
061      // Indicates whether the search was unindexed.
062      private final Boolean isUnindexed;
063    
064      // Indicates whether the any uncached data was accessed in the course of
065      // processing this operation.
066      private final Boolean uncachedDataAccessed;
067    
068      // The processing time for the operation.
069      private final Double processingTime;
070    
071      // The queue time for the operation.
072      private final Double queueTime;
073    
074      // The list of privileges required for processing the operation that the
075      // requester did not have.
076      private final List<String> missingPrivileges;
077    
078      // The list of privileges used during the course of processing the operation
079      // before an alternate authorization identity was assigned.
080      private final List<String> preAuthZUsedPrivileges;
081    
082      // The list of referral URLs for the operation.
083      private final List<String> referralURLs;
084    
085      // The list of response control OIDs for the operation.
086      private final List<String> responseControlOIDs;
087    
088      // The list of servers accessed while processing the operation.
089      private final List<String> serversAccessed;
090    
091      // The list of privileges used during the course of processing the operation.
092      private final List<String> usedPrivileges;
093    
094      // The number of entries returned to the client.
095      private final Long entriesReturned;
096    
097      // The number of intermediate response messages returned to the client.
098      private final Long intermediateResponsesReturned;
099    
100      // The result code for the operation.
101      private final ResultCode resultCode;
102    
103      // Additional information about the operation result.
104      private final String additionalInformation;
105    
106      // The alternate authorization DN for the operation.
107      private final String authzDN;
108    
109      // The diagnostic message for the operation.
110      private final String diagnosticMessage;
111    
112      // The intermediate client result for the operation.
113      private final String intermediateClientResult;
114    
115      // The matched DN for the operation.
116      private final String matchedDN;
117    
118      // The port of the backend server to which the request has been forwarded.
119      private final Integer targetPort;
120    
121      // The address of the backend server to which the request has been forwarded.
122      private final String targetHost;
123    
124      // The protocol used to forward the request to the backend server.
125      private final String targetProtocol;
126    
127    
128    
129      /**
130       * Creates a new search result access log message from the provided message
131       * string.
132       *
133       * @param  s  The string to be parsed as a search result access log message.
134       *
135       * @throws  LogException  If the provided string cannot be parsed as a valid
136       *                        log message.
137       */
138      public SearchResultAccessLogMessage(final String s)
139             throws LogException
140      {
141        this(new LogMessage(s));
142      }
143    
144    
145    
146      /**
147       * Creates a new search result access log message from the provided log
148       * message.
149       *
150       * @param  m  The log message to be parsed as a search result access log
151       *            message.
152       */
153      public SearchResultAccessLogMessage(final LogMessage m)
154      {
155        super(m);
156    
157        diagnosticMessage        = getNamedValue("message");
158        additionalInformation    = getNamedValue("additionalInfo");
159        matchedDN                = getNamedValue("matchedDN");
160        processingTime           = getNamedValueAsDouble("etime");
161        queueTime                = getNamedValueAsDouble("qtime");
162        intermediateClientResult = getNamedValue("from");
163        entriesReturned          = getNamedValueAsLong("entriesReturned");
164        isUnindexed              = getNamedValueAsBoolean("unindexed");
165        authzDN                  = getNamedValue("authzDN");
166        targetHost               = getNamedValue("targetHost");
167        targetPort               = getNamedValueAsInteger("targetPort");
168        targetProtocol           = getNamedValue("targetProtocol");
169    
170        intermediateResponsesReturned =
171             getNamedValueAsLong("intermediateResponsesReturned");
172    
173        final Integer rcInteger = getNamedValueAsInteger("resultCode");
174        if (rcInteger == null)
175        {
176          resultCode = null;
177        }
178        else
179        {
180          resultCode = ResultCode.valueOf(rcInteger);
181        }
182    
183        final String refStr = getNamedValue("referralURLs");
184        if ((refStr == null) || (refStr.length() == 0))
185        {
186          referralURLs = Collections.emptyList();
187        }
188        else
189        {
190          final LinkedList<String> refs = new LinkedList<String>();
191          int startPos = 0;
192          while (true)
193          {
194            final int commaPos = refStr.indexOf(",ldap", startPos);
195            if (commaPos < 0)
196            {
197              refs.add(refStr.substring(startPos));
198              break;
199            }
200            else
201            {
202              refs.add(refStr.substring(startPos, commaPos));
203              startPos = commaPos+1;
204            }
205          }
206          referralURLs = Collections.unmodifiableList(refs);
207        }
208    
209        final String controlStr = getNamedValue("responseControls");
210        if (controlStr == null)
211        {
212          responseControlOIDs = Collections.emptyList();
213        }
214        else
215        {
216          final LinkedList<String> controlList = new LinkedList<String>();
217          final StringTokenizer t = new StringTokenizer(controlStr, ",");
218          while (t.hasMoreTokens())
219          {
220            controlList.add(t.nextToken());
221          }
222          responseControlOIDs = Collections.unmodifiableList(controlList);
223        }
224    
225        final String serversAccessedStr = getNamedValue("serversAccessed");
226        if ((serversAccessedStr == null) || (serversAccessedStr.length() == 0))
227        {
228          serversAccessed = Collections.emptyList();
229        }
230        else
231        {
232          final LinkedList<String> servers = new LinkedList<String>();
233          final StringTokenizer tokenizer =
234               new StringTokenizer(serversAccessedStr, ",");
235          while (tokenizer.hasMoreTokens())
236          {
237            servers.add(tokenizer.nextToken());
238          }
239          serversAccessed = Collections.unmodifiableList(servers);
240        }
241    
242        uncachedDataAccessed = getNamedValueAsBoolean("uncachedDataAccessed");
243    
244        final String usedPrivilegesStr = getNamedValue("usedPrivileges");
245        if ((usedPrivilegesStr == null) || (usedPrivilegesStr.length() == 0))
246        {
247          usedPrivileges = Collections.emptyList();
248        }
249        else
250        {
251          final LinkedList<String> privileges = new LinkedList<String>();
252          final StringTokenizer tokenizer =
253               new StringTokenizer(usedPrivilegesStr, ",");
254          while (tokenizer.hasMoreTokens())
255          {
256            privileges.add(tokenizer.nextToken());
257          }
258          usedPrivileges = Collections.unmodifiableList(privileges);
259        }
260    
261        final String preAuthZUsedPrivilegesStr =
262             getNamedValue("preAuthZUsedPrivileges");
263        if ((preAuthZUsedPrivilegesStr == null) ||
264            (preAuthZUsedPrivilegesStr.length() == 0))
265        {
266          preAuthZUsedPrivileges = Collections.emptyList();
267        }
268        else
269        {
270          final LinkedList<String> privileges = new LinkedList<String>();
271          final StringTokenizer tokenizer =
272               new StringTokenizer(preAuthZUsedPrivilegesStr, ",");
273          while (tokenizer.hasMoreTokens())
274          {
275            privileges.add(tokenizer.nextToken());
276          }
277          preAuthZUsedPrivileges = Collections.unmodifiableList(privileges);
278        }
279    
280        final String missingPrivilegesStr = getNamedValue("missingPrivileges");
281        if ((missingPrivilegesStr == null) || (missingPrivilegesStr.length() == 0))
282        {
283          missingPrivileges = Collections.emptyList();
284        }
285        else
286        {
287          final LinkedList<String> privileges = new LinkedList<String>();
288          final StringTokenizer tokenizer =
289               new StringTokenizer(missingPrivilegesStr, ",");
290          while (tokenizer.hasMoreTokens())
291          {
292            privileges.add(tokenizer.nextToken());
293          }
294          missingPrivileges = Collections.unmodifiableList(privileges);
295        }
296      }
297    
298    
299    
300      /**
301       * Retrieves the result code for the operation.
302       *
303       * @return  The result code for the operation, or {@code null} if it is not
304       *          included in the log message.
305       */
306      public ResultCode getResultCode()
307      {
308        return resultCode;
309      }
310    
311    
312    
313      /**
314       * Retrieves the diagnostic message for the operation.
315       *
316       * @return  The diagnostic message for the operation, or {@code null} if it is
317       *          not included in the log message.
318       */
319      public String getDiagnosticMessage()
320      {
321        return diagnosticMessage;
322      }
323    
324    
325    
326      /**
327       * Retrieves a message with additional information about the result of the
328       * operation.
329       *
330       * @return  A message with additional information about the result of the
331       *          operation, or {@code null} if it is not included in the log
332       *          message.
333       */
334      public String getAdditionalInformation()
335      {
336        return additionalInformation;
337      }
338    
339    
340    
341      /**
342       * Retrieves the matched DN for the operation.
343       *
344       * @return  The matched DN for the operation, or {@code null} if it is not
345       *          included in the log message.
346       */
347      public String getMatchedDN()
348      {
349        return matchedDN;
350      }
351    
352    
353    
354      /**
355       * Retrieves the list of referral URLs for the operation.
356       *
357       * @return  The list of referral URLs for the operation, or an empty list if
358       *          it is not included in the log message.
359       */
360      public List<String> getReferralURLs()
361      {
362        return referralURLs;
363      }
364    
365    
366    
367      /**
368       * Retrieves the number of intermediate response messages returned in the
369       * course of processing the operation.
370       *
371       * @return  The number of intermediate response messages returned to the
372       *          client in the course of processing the operation, or {@code null}
373       *          if it is not included in the log message.
374       */
375      public Long getIntermediateResponsesReturned()
376      {
377        return intermediateResponsesReturned;
378      }
379    
380    
381    
382      /**
383       * Retrieves the length of time in milliseconds required to process the
384       * operation.
385       *
386       * @return  The length of time in milliseconds required to process the
387       *          operation, or {@code null} if it is not included in the log
388       *          message.
389       */
390      public Double getProcessingTimeMillis()
391      {
392        return processingTime;
393      }
394    
395    
396    
397      /**
398       * Retrieves the length of time in milliseconds the operation was required to
399       * wait on the work queue.
400       *
401       * @return  The length of time in milliseconds the operation was required to
402       *          wait on the work queue, or {@code null} if it is not included in
403       *          the log message.
404       */
405      public Double getQueueTimeMillis()
406      {
407        return queueTime;
408      }
409    
410    
411    
412      /**
413       * Retrieves the OIDs of any response controls contained in the log message.
414       *
415       * @return  The OIDs of any response controls contained in the log message, or
416       *          an empty list if it is not included in the log message.
417       */
418      public List<String> getResponseControlOIDs()
419      {
420        return responseControlOIDs;
421      }
422    
423    
424    
425      /**
426       * Retrieves a list of the additional servers that were accessed in the course
427       * of processing the operation.  For example, if the access log message is
428       * from a Directory Proxy Server instance, then this may contain a list of the
429       * backend servers used to process the operation.
430       *
431       * @return  A list of the additional servers that were accessed in the course
432       *          of processing the operation, or an empty list if it is not
433       *          included in the log message.
434       */
435      public List<String> getServersAccessed()
436      {
437        return serversAccessed;
438      }
439    
440    
441    
442      /**
443       * Indicates whether the server accessed any uncached data in the course of
444       * processing the operation.
445       *
446       * @return  {@code true} if the server was known to access uncached data in
447       *          the course of processing the operation, {@code false} if the
448       *          server was known not to access uncached data, or {@code null} if
449       *          it is not included in the log message (and the server likely did
450       *          not access uncached data).
451       */
452      public Boolean getUncachedDataAccessed()
453      {
454        return uncachedDataAccessed;
455      }
456    
457    
458    
459      /**
460       * Retrieves the content of the intermediate client result for the
461       * operation.
462       *
463       * @return  The content of the intermediate client result for the operation,
464       *          or {@code null} if it is not included in the log message.
465       */
466      public String getIntermediateClientResult()
467      {
468        return intermediateClientResult;
469      }
470    
471    
472    
473      /**
474       * Retrieves the number of entries returned to the client.
475       *
476       * @return  The number of entries returned to the client, or {@code null} if
477       *          it is not included in the log message.
478       */
479      public Long getEntriesReturned()
480      {
481        return entriesReturned;
482      }
483    
484    
485    
486      /**
487       * Indicates whether the search was unindexed.
488       *
489       * @return  {@code Boolean.TRUE} if the search was unindexed,
490       *          {@code Boolean.FALSE} if it was not, or {@code null} if it is not
491       *          included in the log message.
492       */
493      public Boolean isUnindexed()
494      {
495        return isUnindexed;
496      }
497    
498    
499    
500      /**
501       * Retrieves the alternate authorization DN for the operation.
502       *
503       * @return  The alternate authorization DN for the operation, or {@code null}
504       *          if it is not included in the log message.
505       */
506      public String getAlternateAuthorizationDN()
507      {
508        return authzDN;
509      }
510    
511    
512    
513      /**
514       * Retrieves the address of the backend server to which the request has been
515       * forwarded.
516       *
517       * @return  The address of the backend server to which the request has been
518       *          forwarded, or {@code null} if it is not included in the log
519       *          message.
520       */
521      public String getTargetHost()
522      {
523        return targetHost;
524      }
525    
526    
527    
528      /**
529       * Retrieves the port of the backend server to which the request has been
530       * forwarded.
531       *
532       * @return  The port of the backend server to which the request has been
533       *          forwarded, or {@code null} if it is not included in the log
534       *          message.
535       */
536      public Integer getTargetPort()
537      {
538        return targetPort;
539      }
540    
541    
542    
543      /**
544       * Retrieves the protocol used to forward the request to the backend server.
545       *
546       * @return  The protocol used to forward the request to the backend server, or
547       *          {@code null} if it is not included in the log message.
548       */
549      public String getTargetProtocol()
550      {
551        return targetProtocol;
552      }
553    
554    
555    
556      /**
557       * Retrieves the names of any privileges used during the course of processing
558       * the operation.
559       *
560       * @return  The names of any privileges used during the course of processing
561       *          the operation, or an empty list if no privileges were used or this
562       *          is not included in the log message.
563       */
564      public List<String> getUsedPrivileges()
565      {
566        return usedPrivileges;
567      }
568    
569    
570    
571      /**
572       * Retrieves the names of any privileges used during the course of processing
573       * the operation before an alternate authorization identity was assigned.
574       *
575       * @return  The names of any privileges used during the course of processing
576       *          the operation before an alternate authorization identity was
577       *          assigned, or an empty list if no privileges were used or this is
578       *          not included in the log message.
579       */
580      public List<String> getPreAuthorizationUsedPrivileges()
581      {
582        return preAuthZUsedPrivileges;
583      }
584    
585    
586    
587      /**
588       * Retrieves the names of any privileges that would have been required for
589       * processing the operation but that the requester did not have.
590       *
591       * @return  The names of any privileges that would have been required for
592       *          processing the operation but that the requester did not have, or
593       *          an empty list if there were no missing privileges or this is not
594       *          included in the log message.
595       */
596      public List<String> getMissingPrivileges()
597      {
598        return missingPrivileges;
599      }
600    
601    
602    
603      /**
604       * {@inheritDoc}
605       */
606      @Override()
607      public AccessLogMessageType getMessageType()
608      {
609        return AccessLogMessageType.RESULT;
610      }
611    }