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.List;
041
042import com.unboundid.asn1.ASN1OctetString;
043import com.unboundid.ldap.sdk.Control;
044import com.unboundid.ldap.sdk.DecodeableControl;
045import com.unboundid.ldap.sdk.JSONControlDecodeHelper;
046import com.unboundid.ldap.sdk.LDAPException;
047import com.unboundid.ldap.sdk.LDAPResult;
048import com.unboundid.ldap.sdk.ResultCode;
049import com.unboundid.ldap.sdk.SearchResultEntry;
050import com.unboundid.ldap.sdk.SearchResultReference;
051import com.unboundid.util.NotMutable;
052import com.unboundid.util.NotNull;
053import com.unboundid.util.Nullable;
054import com.unboundid.util.ThreadSafety;
055import com.unboundid.util.ThreadSafetyLevel;
056import com.unboundid.util.Validator;
057import com.unboundid.util.json.JSONField;
058import com.unboundid.util.json.JSONObject;
059
060import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
061
062
063
064/**
065 * This class provides a response control that may be used to provide the server
066 * ID of the Directory Server instance that processed the associated request.
067 * For search operations, each entry and reference returned will include the
068 * server ID of the server that provided that entry or reference.  For all other
069 * types of operations, it will be in the {@code LDAPResult} (or appropriate
070 * subclass) returned for that operation.
071 * <BR>
072 * <BLOCKQUOTE>
073 *   <B>NOTE:</B>  This class, and other classes within the
074 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
075 *   supported for use against Ping Identity, UnboundID, and
076 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
077 *   for proprietary functionality or for external specifications that are not
078 *   considered stable or mature enough to be guaranteed to work in an
079 *   interoperable way with other types of LDAP servers.
080 * </BLOCKQUOTE>
081 * <BR>
082 * This control has an OID of 1.3.6.1.4.1.30221.2.5.15 and a criticality of
083 * false.  This control must have a value, which will simply be the string
084 * representation of the server ID of the associated server.
085 */
086@NotMutable()
087@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
088public final class GetServerIDResponseControl
089       extends Control
090       implements DecodeableControl
091{
092  /**
093   * The OID (1.3.6.1.4.1.30221.2.5.15) for the get server ID response control.
094   */
095  @NotNull public static final String GET_SERVER_ID_RESPONSE_OID =
096       "1.3.6.1.4.1.30221.2.5.15";
097
098
099
100  /**
101   * The name of the field used to hold the server ID in the JSON representation
102   * of this control.
103   */
104  @NotNull private static final String JSON_FIELD_SERVER_ID = "server-id";
105
106
107  /**
108   * The serial version UID for this serializable class.
109   */
110  private static final long serialVersionUID = 5271084342514677677L;
111
112
113
114  // The server ID of the server that processed the associated request.
115  @NotNull private final String serverID;
116
117
118
119  /**
120   * Creates a new empty control instance that is intended to be used only for
121   * decoding controls via the {@code DecodeableControl} interface.
122   */
123  GetServerIDResponseControl()
124  {
125    serverID = null;
126  }
127
128
129
130  /**
131   * Creates a new get server ID response control with the provided server ID.
132   *
133   * @param  serverID  The server ID of the server that processed the associated
134   *                   request.  It must not be {@code null}.
135   */
136  public GetServerIDResponseControl(@NotNull final String serverID)
137  {
138    super(GET_SERVER_ID_RESPONSE_OID, false, new ASN1OctetString(serverID));
139
140    Validator.ensureNotNull(serverID);
141
142    this.serverID = serverID;
143  }
144
145
146
147  /**
148   * Creates a new get server ID response control decoded from the given generic
149   * control contents.
150   *
151   * @param  oid         The OID for the control.
152   * @param  isCritical  Indicates whether this control should be marked
153   *                     critical.
154   * @param  value       The value for the control.  It may be {@code null} if
155   *                     the control to decode does not have a value.
156   *
157   * @throws  LDAPException  If a problem occurs while attempting to decode the
158   *                         generic control as a get server ID response
159   *                         control.
160   */
161  public GetServerIDResponseControl(@NotNull final String oid,
162                                    final boolean isCritical,
163                                    @Nullable final ASN1OctetString value)
164         throws LDAPException
165  {
166    super(oid, isCritical, value);
167
168    if (value == null)
169    {
170      throw new LDAPException(ResultCode.DECODING_ERROR,
171           ERR_GET_SERVER_ID_RESPONSE_MISSING_VALUE.get());
172    }
173
174    serverID = value.stringValue();
175  }
176
177
178
179  /**
180   * {@inheritDoc}
181   */
182  @Override()
183  @NotNull()
184  public GetServerIDResponseControl decodeControl(@NotNull final String oid,
185              final boolean isCritical,
186              @Nullable final ASN1OctetString value)
187         throws LDAPException
188  {
189    return new GetServerIDResponseControl(oid, isCritical, value);
190  }
191
192
193
194  /**
195   * Extracts a get server ID response control from the provided result.
196   *
197   * @param  result  The result from which to retrieve the get server ID
198   *                 response control.
199   *
200   * @return  The get server ID response control contained in the provided
201   *          result, or {@code null} if the result did not contain a get server
202   *          ID response control.
203   *
204   * @throws  LDAPException  If a problem is encountered while attempting to
205   *                         decode the get server ID response control contained
206   *                         in the provided result.
207   */
208  @Nullable()
209  public static GetServerIDResponseControl get(@NotNull final LDAPResult result)
210         throws LDAPException
211  {
212    final Control c = result.getResponseControl(GET_SERVER_ID_RESPONSE_OID);
213    if (c == null)
214    {
215      return null;
216    }
217
218    if (c instanceof GetServerIDResponseControl)
219    {
220      return (GetServerIDResponseControl) c;
221    }
222    else
223    {
224      return new GetServerIDResponseControl(c.getOID(), c.isCritical(),
225           c.getValue());
226    }
227  }
228
229
230
231  /**
232   * Extracts a get server ID response control from the provided search result
233   * entry.
234   *
235   * @param  entry  The search result entry from which to retrieve the get
236   *                server ID response control.
237   *
238   * @return  The get server ID response control contained in the provided
239   *          search result entry, or {@code null} if the entry did not contain
240   *          a get server ID response control.
241   *
242   * @throws  LDAPException  If a problem is encountered while attempting to
243   *                         decode the get server ID response control contained
244   *                         in the provided entry.
245   */
246  @Nullable()
247  public static GetServerIDResponseControl get(
248                     @NotNull final SearchResultEntry entry)
249         throws LDAPException
250  {
251    final Control c = entry.getControl(GET_SERVER_ID_RESPONSE_OID);
252    if (c == null)
253    {
254      return null;
255    }
256
257    if (c instanceof GetServerIDResponseControl)
258    {
259      return (GetServerIDResponseControl) c;
260    }
261    else
262    {
263      return new GetServerIDResponseControl(c.getOID(), c.isCritical(),
264           c.getValue());
265    }
266  }
267
268
269
270  /**
271   * Extracts a get server ID response control from the provided search result
272   * reference.
273   *
274   * @param  ref  The search result reference from which to retrieve the get
275   *              server ID response control.
276   *
277   * @return  The get server ID response control contained in the provided
278   *          search result reference, or {@code null} if the reference did not
279   *          contain a get server ID response control.
280   *
281   * @throws  LDAPException  If a problem is encountered while attempting to
282   *                         decode the get server ID response control contained
283   *                         in the provided reference.
284   */
285  @Nullable()
286  public static GetServerIDResponseControl get(
287                     @NotNull final SearchResultReference ref)
288         throws LDAPException
289  {
290    final Control c = ref.getControl(GET_SERVER_ID_RESPONSE_OID);
291    if (c == null)
292    {
293      return null;
294    }
295
296    if (c instanceof GetServerIDResponseControl)
297    {
298      return (GetServerIDResponseControl) c;
299    }
300    else
301    {
302      return new GetServerIDResponseControl(c.getOID(), c.isCritical(),
303           c.getValue());
304    }
305  }
306
307
308
309  /**
310   * Retrieves the server ID of the server that actually processed the
311   * associated request.
312   *
313   * @return  The server ID of the server that actually processed the associated
314   *          request.
315   */
316  @NotNull()
317  public String getServerID()
318  {
319    return serverID;
320  }
321
322
323
324  /**
325   * {@inheritDoc}
326   */
327  @Override()
328  @NotNull()
329  public String getControlName()
330  {
331    return INFO_CONTROL_NAME_GET_SERVER_ID_RESPONSE.get();
332  }
333
334
335
336  /**
337   * Retrieves a representation of this get server ID response control as a JSON
338   * object.  The JSON object uses the following fields:
339   * <UL>
340   *   <LI>
341   *     {@code oid} -- A mandatory string field whose value is the object
342   *     identifier for this control.  For the get server ID response control,
343   *     the OID is "1.3.6.1.4.1.30221.2.5.15".
344   *   </LI>
345   *   <LI>
346   *     {@code control-name} -- An optional string field whose value is a
347   *     human-readable name for this control.  This field is only intended for
348   *     descriptive purposes, and when decoding a control, the {@code oid}
349   *     field should be used to identify the type of control.
350   *   </LI>
351   *   <LI>
352   *     {@code criticality} -- A mandatory Boolean field used to indicate
353   *     whether this control is considered critical.
354   *   </LI>
355   *   <LI>
356   *     {@code value-base64} -- An optional string field whose value is a
357   *     base64-encoded representation of the raw value for this get server ID
358   *     response control.  Exactly one of the {@code value-base64} and
359   *     {@code value-json} fields must be present.
360   *   </LI>
361   *   <LI>
362   *     {@code value-json} -- An optional JSON object field whose value is a
363   *     user-friendly representation of the value for this get server ID
364   *     response control.  Exactly one of the {@code value-base64} and
365   *     {@code value-json} fields must be present, and if the
366   *     {@code value-json} field is used, then it will use the following
367   *     fields:
368   *     <UL>
369   *       <LI>
370   *         {@code server-id} -- A string field whose value is the server ID
371   *         for the server that processed the operation or returned the entry.
372   *       </LI>
373   *     </UL>
374   *   </LI>
375   * </UL>
376   *
377   * @return  A JSON object that contains a representation of this control.
378   */
379  @Override()
380  @NotNull()
381  public JSONObject toJSONControl()
382  {
383    return new JSONObject(
384         new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID,
385              GET_SERVER_ID_RESPONSE_OID),
386         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME,
387              INFO_CONTROL_NAME_GET_SERVER_ID_RESPONSE.get()),
388         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY,
389              isCritical()),
390         new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON,
391              new JSONObject(
392                   new JSONField(JSON_FIELD_SERVER_ID, serverID))));
393  }
394
395
396
397  /**
398   * Attempts to decode the provided object as a JSON representation of a get
399   * server ID response control.
400   *
401   * @param  controlObject  The JSON object to be decoded.  It must not be
402   *                        {@code null}.
403   * @param  strict         Indicates whether to use strict mode when decoding
404   *                        the provided JSON object.  If this is {@code true},
405   *                        then this method will throw an exception if the
406   *                        provided JSON object contains any unrecognized
407   *                        fields.  If this is {@code false}, then unrecognized
408   *                        fields will be ignored.
409   *
410   * @return  The get server ID response control that was decoded from the
411   *          provided JSON object.
412   *
413   * @throws  LDAPException  If the provided JSON object cannot be parsed as a
414   *                         valid get server ID response control.
415   */
416  @NotNull()
417  public static GetServerIDResponseControl decodeJSONControl(
418              @NotNull final JSONObject controlObject,
419              final boolean strict)
420         throws LDAPException
421  {
422    final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper(
423         controlObject, strict, true, true);
424
425    final ASN1OctetString rawValue = jsonControl.getRawValue();
426    if (rawValue != null)
427    {
428      return new GetServerIDResponseControl(jsonControl.getOID(),
429           jsonControl.getCriticality(), rawValue);
430    }
431
432
433    final JSONObject valueObject = jsonControl.getValueObject();
434
435    final String serverID = valueObject.getFieldAsString(JSON_FIELD_SERVER_ID);
436    if (serverID == null)
437    {
438      throw new LDAPException(ResultCode.DECODING_ERROR,
439           ERR_GET_SERVER_ID_RESPONSE_JSON_MISSING_SERVER_ID.get(
440                controlObject.toSingleLineString(), JSON_FIELD_SERVER_ID));
441    }
442
443
444    if (strict)
445    {
446      final List<String> unrecognizedFields =
447           JSONControlDecodeHelper.getControlObjectUnexpectedFields(
448                valueObject, JSON_FIELD_SERVER_ID);
449      if (! unrecognizedFields.isEmpty())
450      {
451        throw new LDAPException(ResultCode.DECODING_ERROR,
452             ERR_GET_SERVER_ID_RESPONSE_JSON_UNRECOGNIZED_FIELD.get(
453                  controlObject.toSingleLineString(),
454                  unrecognizedFields.get(0)));
455      }
456    }
457
458
459    return new GetServerIDResponseControl(serverID);
460  }
461
462
463
464  /**
465   * {@inheritDoc}
466   */
467  @Override()
468  public void toString(@NotNull final StringBuilder buffer)
469  {
470    buffer.append("GetServerIDResponseControl(serverID='");
471    buffer.append(serverID);
472    buffer.append("')");
473  }
474}