001/*
002 * Copyright 2009-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2009-2022 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) 2009-2022 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.JSONControlDecodeHelper;
045import com.unboundid.ldap.sdk.LDAPException;
046import com.unboundid.ldap.sdk.ResultCode;
047import com.unboundid.util.NotMutable;
048import com.unboundid.util.NotNull;
049import com.unboundid.util.Nullable;
050import com.unboundid.util.ThreadSafety;
051import com.unboundid.util.ThreadSafetyLevel;
052import com.unboundid.util.json.JSONField;
053import com.unboundid.util.json.JSONObject;
054
055import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
056
057
058
059/**
060 * This class provides an implementation of a Directory Server control that may
061 * be used to indicate that the associated operation is used for performing some
062 * administrative operation within the server rather than one that was requested
063 * by a "normal" client.  The server can use this indication to treat the
064 * operation differently (e.g., exclude it from the processing time histogram,
065 * or to include additional information about the purpose of the operation in
066 * the access log).
067 * <BR>
068 * <BLOCKQUOTE>
069 *   <B>NOTE:</B>  This class, and other classes within the
070 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
071 *   supported for use against Ping Identity, UnboundID, and
072 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
073 *   for proprietary functionality or for external specifications that are not
074 *   considered stable or mature enough to be guaranteed to work in an
075 *   interoperable way with other types of LDAP servers.
076 * </BLOCKQUOTE>
077 * <BR>
078 * This request control has an OID of 1.3.6.1.4.1.30221.2.5.11 and a criticality
079 * of false.  It may optionally have a value that is simply the bytes that
080 * comprise the message to include in the control.
081 */
082@NotMutable()
083@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
084public final class AdministrativeOperationRequestControl
085       extends Control
086{
087  /**
088   * The name of the JSON field used to hold the message in the JSON
089   * representation of this control.
090   */
091  @NotNull private static final String JSON_FIELD_MESSAGE = "message";
092
093
094
095  /**
096   * The OID (1.3.6.1.4.1.30221.2.5.11) for the administrative operation request
097   * control.
098   */
099  @NotNull public static final String ADMINISTRATIVE_OPERATION_REQUEST_OID =
100       "1.3.6.1.4.1.30221.2.5.11";
101
102
103
104  /**
105   * The serial version UID for this serializable class.
106   */
107  private static final long serialVersionUID = 4958642483402677725L;
108
109
110
111  // The informational message to include in the control, if defined.
112  @Nullable private final String message;
113
114
115
116  /**
117   * Creates a new administrative operation request control with no message.
118   */
119  public AdministrativeOperationRequestControl()
120  {
121    this((String) null);
122  }
123
124
125
126  /**
127   * Creates a new administrative operation request control with the provided
128   * informational message.
129   *
130   * @param  message  A message with additional information about the purpose of
131   *                  the associated operation.  It may be {@code null} if no
132   *                  additional message should be provided.
133   */
134  public AdministrativeOperationRequestControl(@Nullable final String message)
135  {
136    super(ADMINISTRATIVE_OPERATION_REQUEST_OID, false, encodeValue(message));
137
138    this.message = message;
139  }
140
141
142
143  /**
144   * Creates a new administrative operation request control decoded from the
145   * provided generic control.
146   *
147   * @param  control  The generic control to be decoded as an administrative
148   *                  operation request control.
149   */
150  public AdministrativeOperationRequestControl(@NotNull final Control control)
151  {
152    super(control);
153
154    if (control.hasValue())
155    {
156      message = control.getValue().stringValue();
157    }
158    else
159    {
160      message = null;
161    }
162  }
163
164
165
166  /**
167   * Generates an appropriately-encoded value for this control with the provided
168   * message.
169   *
170   * @param  message  A message with additional information about the purpose of
171   *                  the associated operation.  It may be {@code null} if no
172   *                  additional message should be provided.
173   *
174   * @return  An appropriately-encoded value for this control, or {@code null}
175   *          if no value is needed.
176   */
177  @Nullable()
178  private static ASN1OctetString encodeValue(@Nullable final String message)
179  {
180    if (message == null)
181    {
182      return null;
183    }
184    else
185    {
186      return new ASN1OctetString(message);
187    }
188  }
189
190
191
192  /**
193   * Retrieves the informational message for this control, if defined.
194   *
195   * @return  The informational message for this control, or {@code null} if
196   *          none was provided.
197   */
198  @Nullable()
199  public String getMessage()
200  {
201    return message;
202  }
203
204
205
206  /**
207   * {@inheritDoc}
208   */
209  @Override()
210  @NotNull()
211  public String getControlName()
212  {
213    return INFO_CONTROL_NAME_ADMINISTRATIVE_OPERATION_REQUEST.get();
214  }
215
216
217
218  /**
219   * Retrieves a representation of this administrative operation request control
220   * as a JSON object.  The JSON object uses the following fields:
221   * <UL>
222   *   <LI>
223   *     {@code oid} -- A mandatory string field whose value is the object
224   *     identifier for this control.  For the administrative operation request
225   *     control, the OID is "1.3.6.1.4.1.30221.2.5.11".
226   *   </LI>
227   *   <LI>
228   *     {@code control-name} -- An optional string field whose value is a
229   *     human-readable name for this control.  This field is only intended for
230   *     descriptive purposes, and when decoding a control, the {@code oid}
231   *     field should be used to identify the type of control.
232   *   </LI>
233   *   <LI>
234   *     {@code criticality} -- A mandatory Boolean field used to indicate
235   *     whether this control is considered critical.
236   *   </LI>
237   *   <LI>
238   *     {@code value-base64} -- An optional string field whose value is a
239   *     base64-encoded representation of the raw value for this administrative
240   *     operation request control.  At most one of the {@code value-base64} and
241   *     {@code value-json} fields may be present.
242   *   </LI>
243   *   <LI>
244   *     {@code value-json} -- An optional JSON object field whose value is a
245   *     user-friendly representation of the value for this administrative
246   *     operation request control.  At most one of the {@code value-base64} and
247   *     {@code value-json} fields may be present, and if the {@code value-json}
248   *     field is used, then it will use the following fields:
249   *     <UL>
250   *       <LI>
251   *         {@code message} -- An optional string field whose value is a
252   *         message that may be used to describe the purpose of the operation.
253   *       </LI>
254   *     </UL>
255   *   </LI>
256   * </UL>
257   *
258   * @return  A JSON object that contains a representation of this control.
259   */
260  @Override()
261  @NotNull()
262  public JSONObject toJSONControl()
263  {
264    final JSONObject valueObject;
265    if (message == null)
266    {
267      valueObject = JSONObject.EMPTY_OBJECT;
268    }
269    else
270    {
271      valueObject = new JSONObject(new JSONField(JSON_FIELD_MESSAGE, message));
272    }
273
274    return new JSONObject(
275         new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID,
276              ADMINISTRATIVE_OPERATION_REQUEST_OID),
277         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME,
278              INFO_CONTROL_NAME_ADMINISTRATIVE_OPERATION_REQUEST.get()),
279         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY,
280              isCritical()),
281         new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON,
282              valueObject));
283  }
284
285
286
287  /**
288   * Attempts to decode the provided object as a JSON representation of an
289   * administrative operation request control.
290   *
291   * @param  controlObject  The JSON object to be decoded.  It must not be
292   *                        {@code null}.
293   * @param  strict         Indicates whether to use strict mode when decoding
294   *                        the provided JSON object.  If this is {@code true},
295   *                        then this method will throw an exception if the
296   *                        provided JSON object contains any unrecognized
297   *                        fields.  If this is {@code false}, then unrecognized
298   *                        fields will be ignored.
299   *
300   * @return  The administrative operation request control that was decoded from
301   *          the provided JSON object.
302   *
303   * @throws  LDAPException  If the provided JSON object cannot be parsed as a
304   *                         valid administrative operation request control.
305   */
306  @NotNull()
307  public static AdministrativeOperationRequestControl decodeJSONControl(
308              @NotNull final JSONObject controlObject,
309              final boolean strict)
310         throws LDAPException
311  {
312    final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper(
313         controlObject, strict, true, false);
314
315    final ASN1OctetString rawValue = jsonControl.getRawValue();
316    if (rawValue != null)
317    {
318      return new AdministrativeOperationRequestControl(new Control(
319           jsonControl.getOID(), jsonControl.getCriticality(), rawValue));
320    }
321
322    final JSONObject valueObject = jsonControl.getValueObject();
323    if (valueObject == null)
324    {
325      return new AdministrativeOperationRequestControl();
326    }
327
328    final String message = valueObject.getFieldAsString(JSON_FIELD_MESSAGE);
329
330
331    if (strict)
332    {
333      final List<String> unrecognizedFields =
334           JSONControlDecodeHelper.getControlObjectUnexpectedFields(
335                valueObject, JSON_FIELD_MESSAGE);
336      if (! unrecognizedFields.isEmpty())
337      {
338        throw new LDAPException(ResultCode.DECODING_ERROR,
339             ERR_ADMIN_OP_REQUEST_JSON_CONTROL_UNRECOGNIZED_FIELD.get(
340                  controlObject.toSingleLineString(),
341                  unrecognizedFields.get(0)));
342      }
343    }
344
345
346    return new AdministrativeOperationRequestControl(message);
347  }
348
349
350
351  /**
352   * {@inheritDoc}
353   */
354  @Override()
355  public void toString(@NotNull final StringBuilder buffer)
356  {
357    buffer.append("AdministrativeOperationRequestControl(");
358
359    if (message != null)
360    {
361      buffer.append("message='");
362      buffer.append(message);
363      buffer.append('\'');
364    }
365
366    buffer.append(')');
367  }
368}