001    /*
002     * Copyright 2008-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.controls;
022    
023    
024    
025    import java.io.Serializable;
026    import java.util.ArrayList;
027    
028    import com.unboundid.asn1.ASN1Boolean;
029    import com.unboundid.asn1.ASN1Constants;
030    import com.unboundid.asn1.ASN1Element;
031    import com.unboundid.asn1.ASN1OctetString;
032    import com.unboundid.asn1.ASN1Sequence;
033    import com.unboundid.ldap.sdk.LDAPException;
034    import com.unboundid.ldap.sdk.ResultCode;
035    import com.unboundid.util.NotMutable;
036    import com.unboundid.util.ThreadSafety;
037    import com.unboundid.util.ThreadSafetyLevel;
038    
039    import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
040    import static com.unboundid.util.Debug.*;
041    import static com.unboundid.util.StaticUtils.*;
042    
043    
044    
045    /**
046     * <BLOCKQUOTE>
047     *   <B>NOTE:</B>  This class is part of the Commercial Edition of the UnboundID
048     *   LDAP SDK for Java.  It is not available for use in applications that
049     *   include only the Standard Edition of the LDAP SDK, and is not supported for
050     *   use in conjunction with non-UnboundID products.
051     * </BLOCKQUOTE>
052     * This class implements a data structure which encapsulates the value of an
053     * intermediate client request value.  It may recursively embed intermediate
054     * client request values from downstream clients.
055     * <BR><BR>
056     * See the documentation in the {@link IntermediateClientRequestControl} class
057     * for an example of using the intermediate client request and response
058     * controls.
059     */
060    @NotMutable()
061    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
062    public final class IntermediateClientRequestValue
063           implements Serializable
064    {
065      /**
066       * The BER type for the downstreamRequest element.
067       */
068      private static final byte TYPE_DOWNSTREAM_REQUEST = (byte) 0xA0;
069    
070    
071    
072      /**
073       * The BER type for the downstreamClientAddress element.
074       */
075      private static final byte TYPE_DOWNSTREAM_CLIENT_ADDRESS = (byte) 0x81;
076    
077    
078    
079      /**
080       * The BER type for the downstreamClientSecure element.
081       */
082      private static final byte TYPE_DOWNSTREAM_CLIENT_SECURE = (byte) 0x82;
083    
084    
085    
086      /**
087       * The BER type for the clientIdentity element.
088       */
089      private static final byte TYPE_CLIENT_IDENTITY = (byte) 0x83;
090    
091    
092    
093      /**
094       * The BER type for the clientName element.
095       */
096      private static final byte TYPE_CLIENT_NAME = (byte) 0x84;
097    
098    
099    
100      /**
101       * The BER type for the clientSessionID element.
102       */
103      private static final byte TYPE_CLIENT_SESSION_ID = (byte) 0x85;
104    
105    
106    
107      /**
108       * The BER type for the clientRequestID element.
109       */
110      private static final byte TYPE_CLIENT_REQUEST_ID = (byte) 0x86;
111    
112    
113    
114      /**
115       * The serial version UID for this serializable class.
116       */
117      private static final long serialVersionUID = -794887520013838259L;
118    
119    
120    
121      // Indicates whether the communication with the downstream client is secure.
122      private final Boolean downstreamClientSecure;
123    
124      // The downstream request value, if present.
125      private final IntermediateClientRequestValue downstreamRequest;
126    
127      // The requested client authorization identity, if present.
128      private final String clientIdentity;
129    
130      // The downstream client address, if present.
131      private final String downstreamClientAddress;
132    
133      // The client name, which describes the client application, if present.
134      private final String clientName;
135    
136      // The client request ID, if present.
137      private final String clientRequestID;
138    
139      // The client session ID, if present.
140      private final String clientSessionID;
141    
142    
143    
144      /**
145       * Creates a new intermediate client request value with the provided
146       * information.
147       *
148       * @param  downstreamRequest        A wrapped intermediate client request from
149       *                                  a downstream client.  It may be
150       *                                  {@code null} if there is no downstream
151       *                                  request.
152       * @param  downstreamClientAddress  The IP address or resolvable name of the
153       *                                  downstream client system.  It may be
154       *                                  {@code null} if there is no downstream
155       *                                  client or its address is not available.
156       * @param  downstreamClientSecure   Indicates whether communication with the
157       *                                  downstream client is secure.  It may be
158       *                                  {@code null} if there is no downstream
159       *                                  client or it is not known whether the
160       *                                  communication is secure.
161       * @param  clientIdentity           The requested client authorization
162       *                                  identity.  It may be {@code null} if there
163       *                                  is no requested authorization identity.
164       * @param  clientName               An identifier string that summarizes the
165       *                                  client application that created this
166       *                                  intermediate client request.  It may be
167       *                                  {@code null} if that information is not
168       *                                  available.
169       * @param  clientSessionID          A string that may be used to identify the
170       *                                  session in the client application.  It may
171       *                                  be {@code null} if there is no available
172       *                                  session identifier.
173       * @param  clientRequestID          A string that may be used to identify the
174       *                                  request in the client application.  It may
175       *                                  be {@code null} if there is no available
176       *                                  request identifier.
177       */
178      public IntermediateClientRequestValue(
179                  final IntermediateClientRequestValue downstreamRequest,
180                  final String downstreamClientAddress,
181                  final Boolean downstreamClientSecure, final String clientIdentity,
182                  final String clientName, final String clientSessionID,
183                  final String clientRequestID)
184      {
185        this.downstreamRequest       = downstreamRequest;
186        this.downstreamClientAddress = downstreamClientAddress;
187        this.downstreamClientSecure  = downstreamClientSecure;
188        this.clientIdentity          = clientIdentity;
189        this.clientName              = clientName;
190        this.clientSessionID         = clientSessionID;
191        this.clientRequestID         = clientRequestID;
192      }
193    
194    
195    
196      /**
197       * Retrieves the wrapped request from a downstream client, if available.
198       *
199       * @return  The wrapped request from a downstream client, or {@code null} if
200       *          there is none.
201       */
202      public IntermediateClientRequestValue getDownstreamRequest()
203      {
204        return downstreamRequest;
205      }
206    
207    
208    
209      /**
210       * Retrieves the requested client authorization identity, if available.
211       *
212       * @return  The requested client authorization identity, or {@code null} if
213       *          there is none.
214       */
215      public String getClientIdentity()
216      {
217        return clientIdentity;
218      }
219    
220    
221    
222      /**
223       * Retrieves the IP address or resolvable name of the downstream client
224       * system, if available.
225       *
226       * @return  The IP address or resolvable name of the downstream client system,
227       *          or {@code null} if there is no downstream client or its address is
228       *          not available.
229       */
230      public String getDownstreamClientAddress()
231      {
232        return downstreamClientAddress;
233      }
234    
235    
236    
237      /**
238       * Indicates whether the communication with the communication with the
239       * downstream client is secure (i.e., whether communication between the
240       * client application and the downstream client is safe from interpretation or
241       * undetectable alteration by a third party observer or interceptor).
242       *
243       *
244       * @return  {@code Boolean.TRUE} if communication with the downstream client
245       *          is secure, {@code Boolean.FALSE} if it is not secure, or
246       *          {@code null} if there is no downstream client or it is not known
247       *          whether the communication is secure.
248       */
249      public Boolean downstreamClientSecure()
250      {
251        return downstreamClientSecure;
252      }
253    
254    
255    
256      /**
257       * Retrieves a string that identifies the client application that created this
258       * intermediate client request value.
259       *
260       * @return  A string that may be used to identify the client application that
261       *          created this intermediate client request value.
262       */
263      public String getClientName()
264      {
265        return clientName;
266      }
267    
268    
269    
270      /**
271       * Retrieves a string that may be used to identify the session in the client
272       * application.
273       *
274       * @return  A string that may be used to identify the session in the client
275       *          application, or {@code null} if there is none.
276       */
277      public String getClientSessionID()
278      {
279        return clientSessionID;
280      }
281    
282    
283    
284      /**
285       * Retrieves a string that may be used to identify the request in the client
286       * application.
287       *
288       * @return  A string that may be used to identify the request in the client
289       *          application, or {@code null} if there is none.
290       */
291      public String getClientRequestID()
292      {
293        return clientRequestID;
294      }
295    
296    
297    
298      /**
299       * Encodes this intermediate client request value to a form that may be
300       * included in the request control.
301       *
302       * @return  An ASN.1 octet string containing the encoded client request value.
303       */
304      public ASN1Sequence encode()
305      {
306        return encode(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE);
307      }
308    
309    
310    
311      /**
312       * Encodes this intermediate client request value to a form that may be
313       * included in the request control.
314       *
315       * @param  type  The BER type to use for this element.
316       *
317       * @return  An ASN.1 octet string containing the encoded client request value.
318       */
319      private ASN1Sequence encode(final byte type)
320      {
321        final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(7);
322    
323        if (downstreamRequest != null)
324        {
325          elements.add(downstreamRequest.encode(TYPE_DOWNSTREAM_REQUEST));
326        }
327    
328        if (downstreamClientAddress != null)
329        {
330          elements.add(new ASN1OctetString(TYPE_DOWNSTREAM_CLIENT_ADDRESS,
331                                           downstreamClientAddress));
332        }
333    
334        if (downstreamClientSecure != null)
335        {
336          elements.add(new ASN1Boolean(TYPE_DOWNSTREAM_CLIENT_SECURE,
337                                       downstreamClientSecure));
338        }
339    
340        if (clientIdentity != null)
341        {
342          elements.add(new ASN1OctetString(TYPE_CLIENT_IDENTITY, clientIdentity));
343        }
344    
345        if (clientName != null)
346        {
347          elements.add(new ASN1OctetString(TYPE_CLIENT_NAME,  clientName));
348        }
349    
350        if (clientSessionID != null)
351        {
352          elements.add(new ASN1OctetString(TYPE_CLIENT_SESSION_ID,
353                                           clientSessionID));
354        }
355    
356        if (clientRequestID != null)
357        {
358          elements.add(new ASN1OctetString(TYPE_CLIENT_REQUEST_ID,
359                                           clientRequestID));
360        }
361    
362        return new ASN1Sequence(type, elements);
363      }
364    
365    
366    
367      /**
368       * Decodes the provided ASN.1 sequence as an intermediate client request
369       * value.
370       *
371       * @param  sequence  The sequence to be decoded as an intermediate client
372       *                   request value.
373       *
374       * @return  The decoded intermediate client request value.
375       *
376       * @throws  LDAPException  If the provided sequence cannot be decoded as an
377       *                         intermediate client request value.
378       */
379      public static IntermediateClientRequestValue
380                         decode(final ASN1Sequence sequence)
381             throws LDAPException
382      {
383        Boolean                        downstreamClientSecure  = null;
384        IntermediateClientRequestValue downstreamRequest       = null;
385        String                         clientIdentity          = null;
386        String                         downstreamClientAddress = null;
387        String                         clientName              = null;
388        String                         clientRequestID         = null;
389        String                         clientSessionID         = null;
390    
391        for (final ASN1Element element : sequence.elements())
392        {
393          switch (element.getType())
394          {
395            case TYPE_DOWNSTREAM_REQUEST:
396              try
397              {
398                final ASN1Sequence s = ASN1Sequence.decodeAsSequence(element);
399                downstreamRequest = decode(s);
400              }
401              catch (LDAPException le)
402              {
403                debugException(le);
404                throw new LDAPException(ResultCode.DECODING_ERROR,
405                     ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_REQUEST.get(
406                          le.getMessage()), le);
407              }
408              catch (Exception e)
409              {
410                debugException(e);
411                throw new LDAPException(ResultCode.DECODING_ERROR,
412                     ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_REQUEST.get(
413                          String.valueOf(e)), e);
414              }
415              break;
416    
417            case TYPE_DOWNSTREAM_CLIENT_ADDRESS:
418              downstreamClientAddress =
419                   ASN1OctetString.decodeAsOctetString(element).stringValue();
420              break;
421    
422            case TYPE_DOWNSTREAM_CLIENT_SECURE:
423              try
424              {
425                downstreamClientSecure =
426                     ASN1Boolean.decodeAsBoolean(element).booleanValue();
427              }
428              catch (Exception e)
429              {
430                debugException(e);
431                throw new LDAPException(ResultCode.DECODING_ERROR,
432                     ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_SECURE.get(
433                          String.valueOf(e)), e);
434              }
435              break;
436    
437            case TYPE_CLIENT_IDENTITY:
438              clientIdentity =
439                   ASN1OctetString.decodeAsOctetString(element).stringValue();
440              break;
441    
442            case TYPE_CLIENT_NAME:
443              clientName =
444                   ASN1OctetString.decodeAsOctetString(element).stringValue();
445              break;
446    
447            case TYPE_CLIENT_SESSION_ID:
448              clientSessionID =
449                   ASN1OctetString.decodeAsOctetString(element).stringValue();
450              break;
451    
452            case TYPE_CLIENT_REQUEST_ID:
453              clientRequestID =
454                   ASN1OctetString.decodeAsOctetString(element).stringValue();
455              break;
456    
457            default:
458              throw new LDAPException(ResultCode.DECODING_ERROR,
459                   ERR_ICREQ_INVALID_ELEMENT_TYPE.get(toHex(element.getType())));
460          }
461        }
462    
463        return new IntermediateClientRequestValue(downstreamRequest,
464                                                  downstreamClientAddress,
465                                                  downstreamClientSecure,
466                                                  clientIdentity, clientName,
467                                                  clientSessionID, clientRequestID);
468      }
469    
470    
471    
472      /**
473       * Generates a hash code for this intermediate client request value.
474       *
475       * @return  A hash code for this intermediate client request value.
476       */
477      @Override()
478      public int hashCode()
479      {
480        int hashCode = 0;
481    
482        if (downstreamRequest != null)
483        {
484          hashCode += downstreamRequest.hashCode();
485        }
486    
487        if (downstreamClientAddress != null)
488        {
489          hashCode += downstreamClientAddress.hashCode();
490        }
491    
492        if (downstreamClientSecure != null)
493        {
494          hashCode += downstreamClientSecure.hashCode();
495        }
496    
497        if (clientIdentity != null)
498        {
499          hashCode += clientIdentity.hashCode();
500        }
501    
502        if (clientName != null)
503        {
504          hashCode += clientName.hashCode();
505        }
506    
507        if (clientSessionID != null)
508        {
509          hashCode += clientSessionID.hashCode();
510        }
511    
512        if (clientRequestID != null)
513        {
514          hashCode += clientRequestID.hashCode();
515        }
516    
517        return hashCode;
518      }
519    
520    
521    
522      /**
523       * Indicates whether the provided object is equal to this intermediate client
524       * request value.  It will only be considered equal if the provided object is
525       * also an intermediate client request value with all the same fields.
526       *
527       * @param  o  The object for which to make the determination.
528       *
529       * @return  {@code true} if the provided object is considered equal to this
530       *          intermediate client request value, or {@code false} if not.
531       */
532      @Override()
533      public boolean equals(final Object o)
534      {
535        if (o == this)
536        {
537          return true;
538        }
539        else if (o == null)
540        {
541          return false;
542        }
543        else if (! (o instanceof IntermediateClientRequestValue))
544        {
545          return false;
546        }
547    
548        final IntermediateClientRequestValue v = (IntermediateClientRequestValue) o;
549    
550        if (downstreamRequest == null)
551        {
552          if (v.downstreamRequest != null)
553          {
554            return false;
555          }
556        }
557        else
558        {
559          if (! downstreamRequest.equals(v.downstreamRequest))
560          {
561            return false;
562          }
563        }
564    
565        if (downstreamClientAddress == null)
566        {
567          if (v.downstreamClientAddress != null)
568          {
569            return false;
570          }
571        }
572        else
573        {
574          if (! downstreamClientAddress.equals(v.downstreamClientAddress))
575          {
576            return false;
577          }
578        }
579    
580        if (downstreamClientSecure == null)
581        {
582          if (v.downstreamClientSecure != null)
583          {
584            return false;
585          }
586        }
587        else
588        {
589          if (! downstreamClientSecure.equals(v.downstreamClientSecure))
590          {
591            return false;
592          }
593        }
594    
595        if (clientIdentity == null)
596        {
597          if (v.clientIdentity != null)
598          {
599            return false;
600          }
601        }
602        else
603        {
604          if (! clientIdentity.equals(v.clientIdentity))
605          {
606            return false;
607          }
608        }
609    
610        if (clientName == null)
611        {
612          if (v.clientName != null)
613          {
614            return false;
615          }
616        }
617        else
618        {
619          if (! clientName.equals(v.clientName))
620          {
621            return false;
622          }
623        }
624    
625        if (clientSessionID == null)
626        {
627          if (v.clientSessionID != null)
628          {
629            return false;
630          }
631        }
632        else
633        {
634          if (! clientSessionID.equals(v.clientSessionID))
635          {
636            return false;
637          }
638        }
639    
640        if (clientRequestID == null)
641        {
642          if (v.clientRequestID != null)
643          {
644            return false;
645          }
646        }
647        else
648        {
649          if (! clientRequestID.equals(v.clientRequestID))
650          {
651            return false;
652          }
653        }
654    
655        return true;
656      }
657    
658    
659    
660      /**
661       * Retrieves a string representation of this intermediate client request
662       * value.
663       *
664       * @return  A string representation of this intermediate client request value.
665       */
666      @Override()
667      public String toString()
668      {
669        final StringBuilder buffer = new StringBuilder();
670        toString(buffer);
671        return buffer.toString();
672      }
673    
674    
675    
676      /**
677       * Appends a string representation of this intermediate client request value
678       * to the provided buffer.
679       *
680       * @param  buffer  The buffer to which the information is to be appended.
681       */
682      public void toString(final StringBuilder buffer)
683      {
684        buffer.append("IntermediateClientRequestValue(");
685    
686        boolean added = false;
687        if (downstreamRequest != null)
688        {
689          buffer.append("downstreamRequest=");
690          downstreamRequest.toString(buffer);
691          added = true;
692        }
693    
694        if (clientIdentity != null)
695        {
696          if (added)
697          {
698            buffer.append(", ");
699          }
700          else
701          {
702            added = true;
703          }
704    
705          buffer.append("clientIdentity='");
706          buffer.append(clientIdentity);
707          buffer.append('\'');
708        }
709    
710        if (downstreamClientAddress != null)
711        {
712          if (added)
713          {
714            buffer.append(", ");
715          }
716          else
717          {
718            added = true;
719          }
720    
721          buffer.append("downstreamClientAddress='");
722          buffer.append(downstreamClientAddress);
723          buffer.append('\'');
724        }
725    
726        if (downstreamClientSecure != null)
727        {
728          if (added)
729          {
730            buffer.append(", ");
731          }
732          else
733          {
734            added = true;
735          }
736    
737          buffer.append("downstreamClientSecure='");
738          buffer.append(downstreamClientSecure);
739          buffer.append('\'');
740        }
741    
742        if (clientName != null)
743        {
744          if (added)
745          {
746            buffer.append(", ");
747          }
748          else
749          {
750            added = true;
751          }
752    
753          buffer.append("clientName='");
754          buffer.append(clientName);
755          buffer.append('\'');
756        }
757    
758        if (clientSessionID != null)
759        {
760          if (added)
761          {
762            buffer.append(", ");
763          }
764          else
765          {
766            added = true;
767          }
768    
769          buffer.append("clientSessionID='");
770          buffer.append(clientSessionID);
771          buffer.append('\'');
772        }
773    
774        if (clientRequestID != null)
775        {
776          if (added)
777          {
778            buffer.append(", ");
779          }
780          else
781          {
782            added = true;
783          }
784    
785          buffer.append("clientRequestID='");
786          buffer.append(clientRequestID);
787          buffer.append('\'');
788        }
789    
790        buffer.append(')');
791      }
792    }