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 response value.  It may recursively embed intermediate
054     * client response values from upstream servers.
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 IntermediateClientResponseValue
063           implements Serializable
064    {
065      /**
066       * The BER type for the upstreamResponse element.
067       */
068      private static final byte TYPE_UPSTREAM_RESPONSE = (byte) 0xA0;
069    
070    
071    
072      /**
073       * The BER type for the upstreamServerAddress element.
074       */
075      private static final byte TYPE_UPSTREAM_SERVER_ADDRESS = (byte) 0x81;
076    
077    
078    
079      /**
080       * The BER type for the upstreamServerSecure element.
081       */
082      private static final byte TYPE_UPSTREAM_SERVER_SECURE = (byte) 0x82;
083    
084    
085    
086      /**
087       * The BER type for the serverName element.
088       */
089      private static final byte TYPE_SERVER_NAME = (byte) 0x83;
090    
091    
092    
093      /**
094       * The BER type for the serverSessionID element.
095       */
096      private static final byte TYPE_SERVER_SESSION_ID = (byte) 0x84;
097    
098    
099    
100      /**
101       * The BER type for the serverResponseID element.
102       */
103      private static final byte TYPE_SERVER_RESPONSE_ID = (byte) 0x85;
104    
105    
106    
107      /**
108       * The serial version UID for this serializable class.
109       */
110      private static final long serialVersionUID = 5165171788442351399L;
111    
112    
113    
114      // Indicates whether communication with the upstream server is secure.
115      private final Boolean upstreamServerSecure;
116    
117      // The upstream response, if available.
118      private final IntermediateClientResponseValue upstreamResponse;
119    
120      // The server name, which describes the server application, if present.
121      private final String serverName;
122    
123      // The server response ID, if present.
124      private final String serverResponseID;
125    
126      // The server session ID, if present.
127      private final String serverSessionID;
128    
129      // The address of the upstream server, if available.
130      private final String upstreamServerAddress;
131    
132    
133    
134      /**
135       * Creates a new intermediate client response value with the provided
136       * information.
137       *
138       * @param  upstreamResponse       A wrapped intermediate client response from
139       *                                an upstream server.  It may be {@code null}
140       *                                if there is no wrapped upstream response.
141       * @param  upstreamServerAddress  The IP address or resolvable name of the
142       *                                upstream server system.  It may be
143       *                                {@code null} if there is no upstream server
144       *                                or its address is not available.
145       * @param  upstreamServerSecure   Indicates whether communication with the
146       *                                upstream server is secure.  It may be
147       *                                {@code null} if there is no upstream server
148       *                                or it is not known whether the communication
149       *                                is secure.
150       * @param  serverName             An identifier string that summarizes the
151       *                                server application that created this
152       *                                intermediate client response.  It may be
153       *                                {@code null} if that information is not
154       *                                available.
155       * @param  serverSessionID        A string that may be used to identify the
156       *                                session in the server application.  It may
157       *                                be {@code null} if there is no available
158       *                                session identifier.
159       * @param  serverResponseID       A string that may be used to identify the
160       *                                response in the server application.  It may
161       *                                be {@code null} if there is no available
162       *                                response identifier.
163       */
164      public IntermediateClientResponseValue(
165                  final IntermediateClientResponseValue upstreamResponse,
166                  final String upstreamServerAddress,
167                  final Boolean upstreamServerSecure, final String serverName,
168                  final String serverSessionID, final String serverResponseID)
169      {
170        this.upstreamResponse      = upstreamResponse;
171        this.upstreamServerAddress = upstreamServerAddress;
172        this.upstreamServerSecure  = upstreamServerSecure;
173        this.serverName            = serverName;
174        this.serverSessionID       = serverSessionID;
175        this.serverResponseID      = serverResponseID;
176      }
177    
178    
179    
180      /**
181       * Retrieves the wrapped response from an upstream server, if available.
182       *
183       * @return  The wrapped response from an upstream server, or {@code null} if
184       *          there is none.
185       */
186      public IntermediateClientResponseValue getUpstreamResponse()
187      {
188        return upstreamResponse;
189      }
190    
191    
192    
193      /**
194       * Retrieves the IP address or resolvable name of the upstream server system,
195       * if available.
196       *
197       * @return  The IP address or resolvable name of the upstream server system,
198       *          {@code null} if there is no upstream server or its address is not
199       *          available.
200       */
201      public String getUpstreamServerAddress()
202      {
203        return upstreamServerAddress;
204      }
205    
206    
207    
208      /**
209       * Indicates whether the communication with the communication with the
210       * upstream server is secure (i.e., whether communication between the
211       * server application and the upstream server is safe from interpretation or
212       * undetectable alteration by a third party observer or interceptor).
213       *
214       *
215       * @return  {@code Boolean.TRUE} if communication with the upstream server is
216       *          secure, {@code Boolean.FALSE} if it is not secure, or
217       *          {@code null} if there is no upstream server or it is not known
218       *          whether the communication is secure.
219       */
220      public Boolean upstreamServerSecure()
221      {
222        return upstreamServerSecure;
223      }
224    
225    
226    
227      /**
228       * Retrieves a string that identifies the server application that created this
229       * intermediate client response value.
230       *
231       * @return  A string that may be used to identify the server application that
232       *          created this intermediate client response value.
233       */
234      public String getServerName()
235      {
236        return serverName;
237      }
238    
239    
240    
241      /**
242       * Retrieves a string that may be used to identify the session in the server
243       * application.
244       *
245       * @return  A string that may be used to identify the session in the server
246       *          application, or {@code null} if there is none.
247       */
248      public String getServerSessionID()
249      {
250        return serverSessionID;
251      }
252    
253    
254    
255      /**
256       * Retrieves a string that may be used to identify the response in the server
257       * application.
258       *
259       * @return  A string that may be used to identify the response in the server
260       *          application, or {@code null} if there is none.
261       */
262      public String getServerResponseID()
263      {
264        return serverResponseID;
265      }
266    
267    
268    
269      /**
270       * Encodes this intermediate client response value to a form that may be
271       * included in the response control.
272       *
273       * @return  An ASN.1 octet string containing the encoded client response
274       *          value.
275       */
276      public ASN1Sequence encode()
277      {
278        return encode(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE);
279      }
280    
281    
282    
283      /**
284       * Encodes this intermediate client response value to a form that may be
285       * included in the response control.
286       *
287       * @param  type  The BER type to use for this element.
288       *
289       * @return  An ASN.1 octet string containing the encoded client response
290       *          value.
291       */
292      private ASN1Sequence encode(final byte type)
293      {
294        final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(6);
295    
296        if (upstreamResponse != null)
297        {
298          elements.add(upstreamResponse.encode(TYPE_UPSTREAM_RESPONSE));
299        }
300    
301        if (upstreamServerAddress != null)
302        {
303          elements.add(new ASN1OctetString(TYPE_UPSTREAM_SERVER_ADDRESS,
304                                           upstreamServerAddress));
305        }
306    
307        if (upstreamServerSecure != null)
308        {
309          elements.add(new ASN1Boolean(TYPE_UPSTREAM_SERVER_SECURE,
310                                       upstreamServerSecure));
311        }
312    
313        if (serverName != null)
314        {
315          elements.add(new ASN1OctetString(TYPE_SERVER_NAME,  serverName));
316        }
317    
318        if (serverSessionID != null)
319        {
320          elements.add(new ASN1OctetString(TYPE_SERVER_SESSION_ID,
321                                           serverSessionID));
322        }
323    
324        if (serverResponseID != null)
325        {
326          elements.add(new ASN1OctetString(TYPE_SERVER_RESPONSE_ID,
327                                           serverResponseID));
328        }
329    
330        return new ASN1Sequence(type, elements);
331      }
332    
333    
334    
335      /**
336       * Decodes the provided ASN.1 sequence as an intermediate client response
337       * value.
338       *
339       * @param  sequence  The sequence to be decoded as an intermediate client
340       *                   response value.
341       *
342       * @return  The decoded intermediate client response value.
343       *
344       * @throws  LDAPException  If the provided sequence cannot be decoded as an
345       *                         intermediate client response value.
346       */
347      public static IntermediateClientResponseValue
348                         decode(final ASN1Sequence sequence)
349             throws LDAPException
350      {
351        Boolean                         upstreamServerSecure  = null;
352        IntermediateClientResponseValue upstreamResponse      = null;
353        String                          upstreamServerAddress = null;
354        String                          serverName            = null;
355        String                          serverResponseID      = null;
356        String                          serverSessionID       = null;
357    
358        for (final ASN1Element element : sequence.elements())
359        {
360          switch (element.getType())
361          {
362            case TYPE_UPSTREAM_RESPONSE:
363              try
364              {
365                final ASN1Sequence s = ASN1Sequence.decodeAsSequence(element);
366                upstreamResponse = decode(s);
367              }
368              catch (LDAPException le)
369              {
370                debugException(le);
371                throw new LDAPException(ResultCode.DECODING_ERROR,
372                     ERR_ICRESP_CANNOT_DECODE_UPSTREAM_RESPONSE.get(
373                          le.getMessage()), le);
374              }
375              catch (Exception e)
376              {
377                debugException(e);
378                throw new LDAPException(ResultCode.DECODING_ERROR,
379                     ERR_ICRESP_CANNOT_DECODE_UPSTREAM_RESPONSE.get(
380                          String.valueOf(e)), e);
381              }
382              break;
383    
384            case TYPE_UPSTREAM_SERVER_ADDRESS:
385              upstreamServerAddress =
386                   ASN1OctetString.decodeAsOctetString(element).stringValue();
387              break;
388    
389            case TYPE_UPSTREAM_SERVER_SECURE:
390              try
391              {
392                upstreamServerSecure =
393                     ASN1Boolean.decodeAsBoolean(element).booleanValue();
394              }
395              catch (Exception e)
396              {
397                debugException(e);
398                throw new LDAPException(ResultCode.DECODING_ERROR,
399                     ERR_ICRESP_CANNOT_DECODE_UPSTREAM_SECURE.get(
400                          String.valueOf(e)), e);
401              }
402              break;
403    
404            case TYPE_SERVER_NAME:
405              serverName =
406                   ASN1OctetString.decodeAsOctetString(element).stringValue();
407              break;
408    
409            case TYPE_SERVER_SESSION_ID:
410              serverSessionID =
411                   ASN1OctetString.decodeAsOctetString(element).stringValue();
412              break;
413    
414            case TYPE_SERVER_RESPONSE_ID:
415              serverResponseID =
416                   ASN1OctetString.decodeAsOctetString(element).stringValue();
417              break;
418    
419            default:
420              throw new LDAPException(ResultCode.DECODING_ERROR,
421                   ERR_ICRESP_INVALID_ELEMENT_TYPE.get(toHex(element.getType())));
422          }
423        }
424    
425        return new IntermediateClientResponseValue(upstreamResponse,
426                                                   upstreamServerAddress,
427                                                   upstreamServerSecure,
428                                                   serverName, serverSessionID,
429                                                   serverResponseID);
430      }
431    
432    
433    
434      /**
435       * Generates a hash code for this intermediate client response value.
436       *
437       * @return  A hash code for this intermediate client response value.
438       */
439      @Override()
440      public int hashCode()
441      {
442        int hashCode = 0;
443    
444        if (upstreamResponse != null)
445        {
446          hashCode += upstreamResponse.hashCode();
447        }
448    
449        if (upstreamServerAddress != null)
450        {
451          hashCode += upstreamServerAddress.hashCode();
452        }
453    
454        if (upstreamServerSecure != null)
455        {
456          hashCode += upstreamServerSecure.hashCode();
457        }
458    
459        if (serverName != null)
460        {
461          hashCode += serverName.hashCode();
462        }
463    
464        if (serverSessionID != null)
465        {
466          hashCode += serverSessionID.hashCode();
467        }
468    
469        if (serverResponseID != null)
470        {
471          hashCode += serverResponseID.hashCode();
472        }
473    
474        return hashCode;
475      }
476    
477    
478    
479      /**
480       * Indicates whether the provided object is equal to this intermediate client
481       * response value.  It will only be considered equal if the provided object is
482       * also an intermediate client response value with all the same fields.
483       *
484       * @param  o  The object for which to make the determination.
485       *
486       * @return  {@code true} if the provided object is considered equal to this
487       *          intermediate client response value, or {@code false} if not.
488       */
489      @Override()
490      public boolean equals(final Object o)
491      {
492        if (o == this)
493        {
494          return true;
495        }
496        else if (o == null)
497        {
498          return false;
499        }
500        else if (! (o instanceof IntermediateClientResponseValue))
501        {
502          return false;
503        }
504    
505        final IntermediateClientResponseValue v =
506             (IntermediateClientResponseValue) o;
507    
508        if (upstreamResponse == null)
509        {
510          if (v.upstreamResponse != null)
511          {
512            return false;
513          }
514        }
515        else
516        {
517          if (! upstreamResponse.equals(v.upstreamResponse))
518          {
519            return false;
520          }
521        }
522    
523        if (upstreamServerAddress == null)
524        {
525          if (v.upstreamServerAddress != null)
526          {
527            return false;
528          }
529        }
530        else
531        {
532          if (! upstreamServerAddress.equals(v.upstreamServerAddress))
533          {
534            return false;
535          }
536        }
537    
538        if (upstreamServerSecure == null)
539        {
540          if (v.upstreamServerSecure != null)
541          {
542            return false;
543          }
544        }
545        else
546        {
547          if (! upstreamServerSecure.equals(v.upstreamServerSecure))
548          {
549            return false;
550          }
551        }
552    
553        if (serverName == null)
554        {
555          if (v.serverName != null)
556          {
557            return false;
558          }
559        }
560        else
561        {
562          if (! serverName.equals(v.serverName))
563          {
564            return false;
565          }
566        }
567    
568        if (serverSessionID == null)
569        {
570          if (v.serverSessionID != null)
571          {
572            return false;
573          }
574        }
575        else
576        {
577          if (! serverSessionID.equals(v.serverSessionID))
578          {
579            return false;
580          }
581        }
582    
583        if (serverResponseID == null)
584        {
585          if (v.serverResponseID != null)
586          {
587            return false;
588          }
589        }
590        else
591        {
592          if (! serverResponseID.equals(v.serverResponseID))
593          {
594            return false;
595          }
596        }
597    
598        return true;
599      }
600    
601    
602    
603      /**
604       * Retrieves a string representation of this intermediate client response
605       * value.
606       *
607       * @return  A string representation of this intermediate client response
608       *          value.
609       */
610      @Override()
611      public String toString()
612      {
613        final StringBuilder buffer = new StringBuilder();
614        toString(buffer);
615        return buffer.toString();
616      }
617    
618    
619    
620      /**
621       * Appends a string representation of this intermediate client response value
622       * to the provided buffer.
623       *
624       * @param  buffer  The buffer to which the information is to be appended.
625       */
626      public void toString(final StringBuilder buffer)
627      {
628        buffer.append("IntermediateClientResponseValue(");
629    
630        boolean added = false;
631        if (upstreamResponse != null)
632        {
633          buffer.append("upstreamResponse=");
634          upstreamResponse.toString(buffer);
635          added = true;
636        }
637    
638        if (upstreamServerAddress != null)
639        {
640          if (added)
641          {
642            buffer.append(", ");
643          }
644          else
645          {
646            added = true;
647          }
648    
649          buffer.append("upstreamServerAddress='");
650          buffer.append(upstreamServerAddress);
651          buffer.append('\'');
652        }
653    
654        if (upstreamServerSecure != null)
655        {
656          if (added)
657          {
658            buffer.append(", ");
659          }
660          else
661          {
662            added = true;
663          }
664    
665          buffer.append("upstreamServerSecure='");
666          buffer.append(upstreamServerSecure);
667          buffer.append('\'');
668        }
669    
670        if (serverName != null)
671        {
672          if (added)
673          {
674            buffer.append(", ");
675          }
676          else
677          {
678            added = true;
679          }
680    
681          buffer.append("serverName='");
682          buffer.append(serverName);
683          buffer.append('\'');
684        }
685    
686        if (serverSessionID != null)
687        {
688          if (added)
689          {
690            buffer.append(", ");
691          }
692          else
693          {
694            added = true;
695          }
696    
697          buffer.append("serverSessionID='");
698          buffer.append(serverSessionID);
699          buffer.append('\'');
700        }
701    
702        if (serverResponseID != null)
703        {
704          if (added)
705          {
706            buffer.append(", ");
707          }
708          else
709          {
710            added = true;
711          }
712    
713          buffer.append("serverResponseID='");
714          buffer.append(serverResponseID);
715          buffer.append('\'');
716        }
717    
718        buffer.append(')');
719      }
720    }