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