001/*
002 * Copyright 2008-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2008-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk.unboundidds.controls;
037
038
039
040import java.util.LinkedHashMap;
041import java.util.List;
042import java.util.Map;
043
044import com.unboundid.asn1.ASN1Element;
045import com.unboundid.asn1.ASN1OctetString;
046import com.unboundid.asn1.ASN1Sequence;
047import com.unboundid.ldap.sdk.Control;
048import com.unboundid.ldap.sdk.DecodeableControl;
049import com.unboundid.ldap.sdk.JSONControlDecodeHelper;
050import com.unboundid.ldap.sdk.LDAPException;
051import com.unboundid.ldap.sdk.LDAPResult;
052import com.unboundid.ldap.sdk.ResultCode;
053import com.unboundid.util.NotMutable;
054import com.unboundid.util.NotNull;
055import com.unboundid.util.Nullable;
056import com.unboundid.util.StaticUtils;
057import com.unboundid.util.ThreadSafety;
058import com.unboundid.util.ThreadSafetyLevel;
059import com.unboundid.util.json.JSONBoolean;
060import com.unboundid.util.json.JSONField;
061import com.unboundid.util.json.JSONObject;
062import com.unboundid.util.json.JSONString;
063import com.unboundid.util.json.JSONValue;
064
065import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
066
067
068
069/**
070 * This class defines an intermediate client response control, which can be used
071 * to provide a server with information about the client and any downstream
072 * clients that it may have.
073 * <BR>
074 * <BLOCKQUOTE>
075 *   <B>NOTE:</B>  This class, and other classes within the
076 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
077 *   supported for use against Ping Identity, UnboundID, and
078 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
079 *   for proprietary functionality or for external specifications that are not
080 *   considered stable or mature enough to be guaranteed to work in an
081 *   interoperable way with other types of LDAP servers.
082 * </BLOCKQUOTE>
083 * <BR>
084 * This control is not based on any public standard.  It was originally
085 * developed for use with the Ping Identity, UnboundID, and Nokia/Alcatel-Lucent
086 * 8661 Directory Server.  The value of this control uses the following
087 * encoding:
088 * <BR><BR>
089 * <PRE>
090 * IntermediateClientResponse ::= SEQUENCE {
091 *      upstreamResponse       [0] IntermediateClientResponse OPTIONAL,
092 *      upstreamServerAddress  [1] OCTET STRING OPTIONAL,
093 *      upstreamServerSecure   [2] BOOLEAN DEFAULT FALSE,
094 *      serverName             [3] OCTET STRING OPTIONAL,
095 *      serverSessionID        [4] OCTET STRING OPTIONAL,
096 *      serverResponseID       [5] OCTET STRING OPTIONAL,
097 *      ... }
098 * </PRE>
099 * See the documentation in the {@link IntermediateClientRequestControl} class
100 * for an example of using the intermediate client request and response
101 * controls.
102 */
103@NotMutable()
104@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
105public final class IntermediateClientResponseControl
106       extends Control
107       implements DecodeableControl
108{
109  /**
110   * The OID (1.3.6.1.4.1.30221.2.5.2) for the intermediate client response
111   * control.
112   */
113  @NotNull public static final String INTERMEDIATE_CLIENT_RESPONSE_OID =
114       "1.3.6.1.4.1.30221.2.5.2";
115
116
117
118  /**
119   * The name of the field used to hold the server name in the JSON
120   * representation of this control.
121   */
122  @NotNull private static final String JSON_FIELD_SERVER_NAME = "server-name";
123
124
125
126  /**
127   * The name of the field used to hold the server request ID in the JSON
128   * representation of this control.
129   */
130  @NotNull private static final String JSON_FIELD_SERVER_RESPONSE_ID =
131       "server-response-id";
132
133
134
135  /**
136   * The name of the field used to hold the server session ID in the JSON
137   * representation of this control.
138   */
139  @NotNull private static final String JSON_FIELD_SERVER_SESSION_ID =
140       "server-session-id";
141
142
143
144  /**
145   * The name of the field used to hold the upstream response in the JSON
146   * representation of this control.
147   */
148  @NotNull private static final String JSON_FIELD_UPSTREAM_RESPONSE =
149       "upstream-response";
150
151
152
153  /**
154   * The name of the field used to hold the upstream server address in the JSON
155   * representation of this control.
156   */
157  @NotNull private static final String JSON_FIELD_UPSTREAM_SERVER_ADDRESS =
158       "upstream-server-address";
159
160
161
162  /**
163   * The name of the field used to hold the upstream server secure flag in the
164   * JSON representation of this control.
165   */
166  @NotNull private static final String JSON_FIELD_UPSTREAM_SERVER_SECURE =
167       "upstream-server-secure";
168
169
170
171  /**
172   * The serial version UID for this serializable class.
173   */
174  private static final long serialVersionUID = 7476073413872875835L;
175
176
177
178  // The value for this intermediate client response control.
179  @NotNull private final IntermediateClientResponseValue value;
180
181
182
183  /**
184   * Creates a new empty control instance that is intended to be used only for
185   * decoding controls via the {@code DecodeableControl} interface.
186   */
187  IntermediateClientResponseControl()
188  {
189    value = null;
190  }
191
192
193
194  /**
195   * Creates a new intermediate client response control with the provided
196   * information.  It will not be marked critical.
197   *
198   * @param  upstreamResponse       A wrapped intermediate client response from
199   *                                an upstream server.  It may be {@code null}
200   *                                if there is no wrapped upstream response.
201   * @param  upstreamServerAddress  The IP address or resolvable name of the
202   *                                upstream server system.  It may be
203   *                                {@code null} if there is no upstream server
204   *                                or its address is not available.
205   * @param  upstreamServerSecure   Indicates whether communication with the
206   *                                upstream server is secure.  It may be
207   *                                {@code null} if there is no upstream server
208   *                                or it is not known whether the communication
209   *                                is secure.
210   * @param  serverName             An identifier string that summarizes the
211   *                                server application that created this
212   *                                intermediate client response.  It may be
213   *                                {@code null} if that information is not
214   *                                available.
215   * @param  serverSessionID        A string that may be used to identify the
216   *                                session in the server application.  It may
217   *                                be {@code null} if there is no available
218   *                                session identifier.
219   * @param  serverResponseID       A string that may be used to identify the
220   *                                response in the server application.  It may
221   *                                be {@code null} if there is no available
222   *                                response identifier.
223   */
224  public IntermediateClientResponseControl(
225              @Nullable final IntermediateClientResponseValue upstreamResponse,
226              @Nullable final String upstreamServerAddress,
227              @Nullable final Boolean upstreamServerSecure,
228              @Nullable final String serverName,
229              @Nullable final String serverSessionID,
230              @Nullable final String serverResponseID)
231  {
232    this(false,
233         new IntermediateClientResponseValue(upstreamResponse,
234                  upstreamServerAddress, upstreamServerSecure, serverName,
235                  serverSessionID, serverResponseID));
236  }
237
238
239
240  /**
241   * Creates a new intermediate client response control with the provided
242   * information.
243   *
244   * @param  oid         The OID for the control.
245   * @param  isCritical  Indicates whether the control should be marked
246   *                     critical.
247   * @param  value       The encoded value for the control.  This may be
248   *                     {@code null} if no value was provided.
249   *
250   * @throws  LDAPException  If the provided control cannot be decoded as an
251   *                         intermediate client response control.
252   */
253  public IntermediateClientResponseControl(@NotNull final String oid,
254              final boolean isCritical,
255              @Nullable final ASN1OctetString value)
256         throws LDAPException
257  {
258    super(oid, isCritical, value);
259
260    if (value == null)
261    {
262      throw new LDAPException(ResultCode.DECODING_ERROR,
263                              ERR_ICRESP_CONTROL_NO_VALUE.get());
264    }
265
266    final ASN1Sequence valueSequence;
267    try
268    {
269      final ASN1Element valueElement = ASN1Element.decode(value.getValue());
270      valueSequence = ASN1Sequence.decodeAsSequence(valueElement);
271    }
272    catch (final Exception e)
273    {
274      throw new LDAPException(ResultCode.DECODING_ERROR,
275           ERR_ICRESP_CONTROL_VALUE_NOT_SEQUENCE.get(
276                StaticUtils.getExceptionMessage(e)),
277           e);
278    }
279
280    this.value = IntermediateClientResponseValue.decode(valueSequence);
281  }
282
283
284
285  /**
286   * Creates a new intermediate client response control with the provided value.
287   * It will be marked critical.
288   *
289   * @param  value  The value to use for this intermediate client response
290   *                control.  It must not be {@code null}.
291   */
292  public IntermediateClientResponseControl(
293              @NotNull final IntermediateClientResponseValue value)
294  {
295    this(false, value);
296  }
297
298
299
300  /**
301   * Creates a new intermediate client response control with the provided value.
302   *
303   * @param  isCritical  Indicates whether the control should be marked
304   *                     critical.  Response controls should generally not be
305   *                     critical.
306   * @param  value       The value to use for this intermediate client response
307   *                     control.  It must not be {@code null}.
308   */
309  public IntermediateClientResponseControl(final boolean isCritical,
310              @NotNull final IntermediateClientResponseValue value)
311  {
312    super(INTERMEDIATE_CLIENT_RESPONSE_OID, isCritical,
313          new ASN1OctetString(value.encode().encode()));
314
315    this.value = value;
316  }
317
318
319
320  /**
321   * {@inheritDoc}
322   */
323  @Override()
324  @NotNull()
325  public IntermediateClientResponseControl decodeControl(
326              @NotNull final String oid,
327              final boolean isCritical,
328              @Nullable final ASN1OctetString value)
329          throws LDAPException
330  {
331    return new IntermediateClientResponseControl(oid, isCritical, value);
332  }
333
334
335
336  /**
337   * Extracts an intermediate client response control from the provided result.
338   *
339   * @param  result  The result from which to retrieve the intermediate client
340   *                 response control.
341   *
342   * @return  The intermediate client response control contained in the provided
343   *          result, or {@code null} if the result did not contain an
344   *          intermediate client response control.
345   *
346   * @throws  LDAPException  If a problem is encountered while attempting to
347   *                         decode the intermediate client response control
348   *                         contained in the provided result.
349   */
350  @Nullable()
351  public static IntermediateClientResponseControl get(
352                     @NotNull final LDAPResult result)
353         throws LDAPException
354  {
355    final Control c =
356         result.getResponseControl(INTERMEDIATE_CLIENT_RESPONSE_OID);
357    if (c == null)
358    {
359      return null;
360    }
361
362    if (c instanceof IntermediateClientResponseControl)
363    {
364      return (IntermediateClientResponseControl) c;
365    }
366    else
367    {
368      return new IntermediateClientResponseControl(c.getOID(), c.isCritical(),
369           c.getValue());
370    }
371  }
372
373
374
375  /**
376   * Retrieves the value for this intermediate client response.
377   *
378   * @return  The value for this intermediate client response.
379   */
380  @NotNull()
381  public IntermediateClientResponseValue getResponseValue()
382  {
383    return value;
384  }
385
386
387
388  /**
389   * Retrieves the wrapped response from an upstream server, if available.
390   *
391   * @return  The wrapped response from an upstream server, or {@code null} if
392   *          there is none.
393   */
394  @Nullable()
395  public IntermediateClientResponseValue getUpstreamResponse()
396  {
397    return value.getUpstreamResponse();
398  }
399
400
401
402  /**
403   * Retrieves the IP address or resolvable name of the upstream server system,
404   * if available.
405   *
406   * @return  The IP address or resolvable name of the upstream server system,
407   *          {@code null} if there is no upstream server or its address is not
408   *          available.
409   */
410  @Nullable()
411  public String getUpstreamServerAddress()
412  {
413    return value.getUpstreamServerAddress();
414  }
415
416
417
418  /**
419   * Indicates whether the communication with the communication with the
420   * upstream server is secure (i.e., whether communication between the
421   * server application and the upstream server is safe from interpretation or
422   * undetectable alteration by a third party observer or interceptor).
423   *
424   *
425   * @return  {@code Boolean.TRUE} if communication with the upstream server is
426   *          secure, {@code Boolean.FALSE} if it is not secure, or
427   *          {@code null} if there is no upstream server or it is not known
428   *          whether the communication is secure.
429   */
430  @Nullable()
431  public Boolean upstreamServerSecure()
432  {
433    return value.upstreamServerSecure();
434  }
435
436
437
438  /**
439   * Retrieves a string that identifies the server application that created this
440   * intermediate client response value.
441   *
442   * @return  A string that may be used to identify the server application that
443   *          created this intermediate client response value.
444   */
445  @Nullable()
446  public String getServerName()
447  {
448    return value.getServerName();
449  }
450
451
452
453  /**
454   * Retrieves a string that may be used to identify the session in the server
455   * application.
456   *
457   * @return  A string that may be used to identify the session in the server
458   *          application, or {@code null} if there is none.
459   */
460  @Nullable()
461  public String getServerSessionID()
462  {
463    return value.getServerSessionID();
464  }
465
466
467
468  /**
469   * Retrieves a string that may be used to identify the response in the server
470   * application.
471   *
472   * @return  A string that may be used to identify the response in the server
473   *          application, or {@code null} if there is none.
474   */
475  @Nullable()
476  public String getServerResponseID()
477  {
478    return value.getServerResponseID();
479  }
480
481
482
483  /**
484   * {@inheritDoc}
485   */
486  @Override()
487  @NotNull()
488  public String getControlName()
489  {
490    return INFO_CONTROL_NAME_INTERMEDIATE_CLIENT_RESPONSE.get();
491  }
492
493
494
495  /**
496   * Retrieves a representation of this intermediate client response control as
497   * a JSON object.  The JSON object uses the following fields:
498   * <UL>
499   *   <LI>
500   *     {@code oid} -- A mandatory string field whose value is the object
501   *     identifier for this control.  For the intermediate client response
502   *     control, the OID is "1.3.6.1.4.1.30221.2.5.2".
503   *   </LI>
504   *   <LI>
505   *     {@code control-name} -- An optional string field whose value is a
506   *     human-readable name for this control.  This field is only intended for
507   *     descriptive purposes, and when decoding a control, the {@code oid}
508   *     field should be used to identify the type of control.
509   *   </LI>
510   *   <LI>
511   *     {@code criticality} -- A mandatory Boolean field used to indicate
512   *     whether this control is considered critical.
513   *   </LI>
514   *   <LI>
515   *     {@code value-base64} -- An optional string field whose value is a
516   *     base64-encoded representation of the raw value for this intermediate
517   *     client response control.  Exactly one of the {@code value-base64} and
518   *     {@code value-json} fields must be present.
519   *   </LI>
520   *   <LI>
521   *     {@code value-json} -- An optional JSON object field whose value is a
522   *     user-friendly representation of the value for this intermediate client
523   *     response control.  Exactly one of the {@code value-base64} and
524   *     {@code value-json} fields must be present, and if the
525   *     {@code value-json} field is used, then it will use the following
526   *     fields:
527   *     <UL>
528   *       <LI>
529   *         {@code upstream-response} -- An optional JSON object field whose
530   *         content represents an upstream response value.  If present, the
531   *         fields of this object are the same as the fields that may be
532   *         included in the top-level {@code value-json} object (optionally
533   *         including a nested {@code upstream-response} field, if
534   *         appropriate).
535   *       </LI>
536   *       <LI>
537   *         {@code upstream-server-address} -- An optional string field whose
538   *         value is the address of an upstream server to which the requested
539   *         operation was forwarded.
540   *       </LI>
541   *       <LI>
542   *         {@code upstream-server-secure} -- An optional Boolean field that
543   *         indicates whether communication with an upstream server occurred
544   *         over a secure channel.
545   *       </LI>
546   *       <LI>
547   *         {@code server-name} -- An optional string field whose value is the
548   *         name of the application used to process the request.
549   *       </LI>
550   *       <LI>
551   *         {@code server-session-id} -- An optional string field whose value
552   *         is an identifier that the server is using to reference the current
553   *         communication session with the client.
554   *       </LI>
555   *       <LI>
556   *         {@code server-response-id} -- An optional string field whose value
557   *         is an identifier that the server is using to reference the current
558   *         operation being processed.
559   *       </LI>
560   *     </UL>
561   *   </LI>
562   * </UL>
563   *
564   * @return  A JSON object that contains a representation of this control.
565   */
566  @Override()
567  @NotNull()
568  public JSONObject toJSONControl()
569  {
570    return new JSONObject(
571         new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID,
572              INTERMEDIATE_CLIENT_RESPONSE_OID),
573         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME,
574              INFO_CONTROL_NAME_INTERMEDIATE_CLIENT_RESPONSE.get()),
575         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY,
576              isCritical()),
577         new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON,
578              encodeResponseValueJSON(value)));
579  }
580
581
582
583  /**
584   * Encodes the provided intermediate client response value to a JSON object.
585   *
586   * @param  value  The intermediate client response value to be encoded.  It
587   *                must not be {@code null}.
588   *
589   * @return  The JSON object containing the encoded intermediate client
590   *          response value.
591   */
592  @NotNull()
593  private static JSONObject encodeResponseValueJSON(
594               @NotNull final IntermediateClientResponseValue value)
595  {
596    final Map<String,JSONValue> fields = new LinkedHashMap<>();
597
598    final IntermediateClientResponseValue upstreamResponse =
599         value.getUpstreamResponse();
600    if (upstreamResponse != null)
601    {
602      fields.put(JSON_FIELD_UPSTREAM_RESPONSE,
603           encodeResponseValueJSON(upstreamResponse));
604    }
605
606    final String upstreamServerAddress = value.getUpstreamServerAddress();
607    if (upstreamServerAddress != null)
608    {
609      fields.put(JSON_FIELD_UPSTREAM_SERVER_ADDRESS,
610           new JSONString(upstreamServerAddress));
611    }
612
613    final Boolean upstreamServerSecure = value.upstreamServerSecure();
614    if (upstreamServerSecure != null)
615    {
616      fields.put(JSON_FIELD_UPSTREAM_SERVER_SECURE,
617           new JSONBoolean(upstreamServerSecure));
618    }
619    final String serverName = value.getServerName();
620    if (serverName != null)
621    {
622      fields.put(JSON_FIELD_SERVER_NAME, new JSONString(serverName));
623    }
624
625    final String serverSessionID = value.getServerSessionID();
626    if (serverSessionID != null)
627    {
628      fields.put(JSON_FIELD_SERVER_SESSION_ID, new JSONString(serverSessionID));
629    }
630
631    final String serverResponseID = value.getServerResponseID();
632    if (serverResponseID != null)
633    {
634      fields.put(JSON_FIELD_SERVER_RESPONSE_ID,
635           new JSONString(serverResponseID));
636    }
637
638    return new JSONObject(fields);
639  }
640
641
642
643  /**
644   * Attempts to decode the provided object as a JSON representation of an
645   * intermediate client response control.
646   *
647   * @param  controlObject  The JSON object to be decoded.  It must not be
648   *                        {@code null}.
649   * @param  strict         Indicates whether to use strict mode when decoding
650   *                        the provided JSON object.  If this is {@code true},
651   *                        then this method will throw an exception if the
652   *                        provided JSON object contains any unrecognized
653   *                        fields.  If this is {@code false}, then unrecognized
654   *                        fields will be ignored.
655   *
656   * @return  The intermediate client response control that was decoded from
657   *          the provided JSON object.
658   *
659   * @throws  LDAPException  If the provided JSON object cannot be parsed as a
660   *                         valid intermediate client response control.
661   */
662  @NotNull()
663  public static IntermediateClientResponseControl decodeJSONControl(
664              @NotNull final JSONObject controlObject,
665              final boolean strict)
666         throws LDAPException
667  {
668    final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper(
669         controlObject, strict, true, true);
670
671    final ASN1OctetString rawValue = jsonControl.getRawValue();
672    if (rawValue != null)
673    {
674      return new IntermediateClientResponseControl(jsonControl.getOID(),
675           jsonControl.getCriticality(), rawValue);
676    }
677
678
679    final IntermediateClientResponseValue value =
680         decodeIntermediateClientResponseValueJSON(controlObject,
681              jsonControl.getValueObject(), false, strict);
682    return new IntermediateClientResponseControl(jsonControl.getCriticality(),
683         value);
684  }
685
686
687
688  /**
689   * Decodes the provided JSON Object as an intermediate client response value.
690   *
691   * @param  controlObject       The JSON object that represents the entire
692   *                             intermediate client response control.  It must
693   *                             not be {@code null}.
694   * @param  valueObject         The intermediate client response value to
695   *                             decode.  It must not be {@code null}.
696   * @param  isUpstreamResponse  Indicates whether the provided JSON object
697   *                             represents an upstream response.
698   * @param  strict              Indicates whether to use strict mode when
699   *                             decoding the provided JSON object.  If this is
700   *                             {@code true}, then this method will throw an
701   *                             exception if the provided JSON object contains
702   *                             any unrecognized fields.  If this is
703   *                             {@code false}, then unrecognized fields will
704   *                             be ignored.
705   *
706   * @return  The intermediate client response value that was decoded.
707   *
708   * @throws  LDAPException  If the provided JSON object cannot be decoded as an
709   *                         intermediate client response value.
710   */
711  @NotNull()
712  private static IntermediateClientResponseValue
713               decodeIntermediateClientResponseValueJSON(
714                    @NotNull final JSONObject controlObject,
715                    @NotNull final JSONObject valueObject,
716                    final boolean isUpstreamResponse,
717                    final boolean strict)
718          throws LDAPException
719  {
720    final IntermediateClientResponseValue upstreamResponse;
721    final JSONObject upstreamResponseObject =
722         valueObject.getFieldAsObject(JSON_FIELD_UPSTREAM_RESPONSE);
723    if (upstreamResponseObject == null)
724    {
725      upstreamResponse = null;
726    }
727    else
728    {
729      upstreamResponse = decodeIntermediateClientResponseValueJSON(
730           controlObject, upstreamResponseObject, true, strict);
731    }
732
733    final String upstreamServerAddress =
734         valueObject.getFieldAsString(JSON_FIELD_UPSTREAM_SERVER_ADDRESS);
735    final Boolean upstreamServerSecure =
736         valueObject.getFieldAsBoolean(JSON_FIELD_UPSTREAM_SERVER_SECURE);
737    final String serverName =
738         valueObject.getFieldAsString(JSON_FIELD_SERVER_NAME);
739    final String serverSessionID =
740         valueObject.getFieldAsString(JSON_FIELD_SERVER_SESSION_ID);
741    final String serverResponseID =
742         valueObject.getFieldAsString(JSON_FIELD_SERVER_RESPONSE_ID);
743
744
745
746    if (strict)
747    {
748      final List<String> unrecognizedFields =
749           JSONControlDecodeHelper.getControlObjectUnexpectedFields(
750                valueObject, JSON_FIELD_UPSTREAM_RESPONSE,
751                JSON_FIELD_UPSTREAM_SERVER_ADDRESS,
752                JSON_FIELD_UPSTREAM_SERVER_SECURE,
753                JSON_FIELD_SERVER_NAME,
754                JSON_FIELD_SERVER_SESSION_ID,
755                JSON_FIELD_SERVER_RESPONSE_ID);
756      if (! unrecognizedFields.isEmpty())
757      {
758        if (isUpstreamResponse)
759        {
760          throw new LDAPException(ResultCode.DECODING_ERROR,
761               ERR_INTERMEDIATE_CLIENT_RESPONSE_JSON_US_VALUE_UNRECOGNIZED_FIELD
762                    .get(controlObject.toSingleLineString(),
763                         unrecognizedFields.get(0)));
764        }
765        else
766        {
767          throw new LDAPException(ResultCode.DECODING_ERROR,
768               ERR_INTERMEDIATE_CLIENT_RESPONSE_JSON_VALUE_UNRECOGNIZED_FIELD.
769                    get(controlObject.toSingleLineString(),
770                         unrecognizedFields.get(0)));
771        }
772      }
773    }
774
775
776    return new IntermediateClientResponseValue(upstreamResponse,
777         upstreamServerAddress, upstreamServerSecure, serverName,
778         serverSessionID, serverResponseID);
779  }
780
781
782
783  /**
784   * {@inheritDoc}
785   */
786  @Override()
787  public void toString(@NotNull final StringBuilder buffer)
788  {
789    buffer.append("IntermediateClientResponseControl(isCritical=");
790    buffer.append(isCritical());
791    buffer.append(", value=");
792    value.toString(buffer);
793    buffer.append(')');
794  }
795}