001/*
002 * Copyright 2012-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 com.unboundid.asn1.ASN1Boolean;
026import com.unboundid.asn1.ASN1Element;
027import com.unboundid.asn1.ASN1Integer;
028import com.unboundid.asn1.ASN1OctetString;
029import com.unboundid.asn1.ASN1Sequence;
030import com.unboundid.ldap.sdk.Control;
031import com.unboundid.ldap.sdk.DecodeableControl;
032import com.unboundid.ldap.sdk.ExtendedResult;
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 provides a response control that may be used to provide the
047 * client with information about transaction-related information over the
048 * course of the associated operation.
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 * This control has an OID of 1.3.6.1.4.1.30221.2.5.39.  It should have a
061 * criticality of {@code false}, and a value with the following encoding:
062 * <PRE>
063 *   TransactionSettingsResponseValue ::= SEQUENCE {
064 *        numLockConflicts        [0] INTEGER
065 *        backendLockAcquired     [1] BOOLEAN,
066 *        ... }
067 * </PRE>
068 */
069@NotMutable()
070@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
071public final class TransactionSettingsResponseControl
072       extends Control
073       implements DecodeableControl
074{
075  /**
076   * The OID (1.3.6.1.4.1.30221.2.5.39) for the transaction settings response
077   * control.
078   */
079  public static final String TRANSACTION_SETTINGS_RESPONSE_OID =
080       "1.3.6.1.4.1.30221.2.5.39";
081
082
083
084  /**
085   * The BER type for the value element used to hold the number of lock
086   * conflicts encountered during the course of processing.
087   */
088  private static final byte TYPE_NUM_LOCK_CONFLICTS = (byte) 0x80;
089
090
091
092  /**
093   * The BER type for the value element used to hold the number of lock
094   * conflicts encountered during the course of processing.
095   */
096  private static final byte TYPE_BACKEND_LOCK_ACQUIRED = (byte) 0x81;
097
098
099
100  /**
101   * The serial version UID for this serializable class.
102   */
103  private static final long serialVersionUID = 7290122856855738454L;
104
105
106
107  // Indicates whether the exclusive backend lock was acquired at any point
108  // during the course of processing the operation.
109  private final boolean backendLockAcquired;
110
111  // The number of lock conflicts encountered during the course of processing
112  // the operation.
113  private final int numLockConflicts;
114
115
116
117  /**
118   * Creates a new empty control instance that is intended to be used only for
119   * decoding controls via the {@code DecodeableControl} interface.
120   */
121  TransactionSettingsResponseControl()
122  {
123    backendLockAcquired = false;
124    numLockConflicts = -1;
125  }
126
127
128
129  /**
130   * Creates a new transaction settings response control with the provided
131   * information.
132   *
133   * @param  numLockConflicts     The number of lock conflicts encountered
134   *                              during the course of processing the operation.
135   * @param  backendLockAcquired  Indicates whether the exclusive backend lock
136   *                              was acquired at any point during the course of
137   *                              processing the operation.
138   */
139  public TransactionSettingsResponseControl(final int numLockConflicts,
140                                            final boolean backendLockAcquired)
141  {
142    super(TRANSACTION_SETTINGS_RESPONSE_OID, false,
143         encodeValue(numLockConflicts, backendLockAcquired));
144
145    this.numLockConflicts = numLockConflicts;
146    this.backendLockAcquired = backendLockAcquired;
147  }
148
149
150
151  /**
152   * Creates a new transaction settings response control with the provided
153   * information.
154   *
155   * @param  oid         The OID for the control.
156   * @param  isCritical  Indicates whether the control should be considered
157   *                     critical.
158   * @param  value       The value for the control.
159   *
160   * @throws LDAPException  If the provided information cannot be used to
161   *                         create a valid soft delete response control.
162   */
163  public TransactionSettingsResponseControl(final String oid,
164                                            final boolean isCritical,
165                                            final ASN1OctetString value)
166         throws LDAPException
167  {
168    super(oid, isCritical, value);
169
170    if (value == null)
171    {
172      throw new LDAPException(ResultCode.DECODING_ERROR,
173           ERR_TXN_SETTINGS_RESPONSE_NO_VALUE.get());
174    }
175
176    try
177    {
178      final ASN1Element[] elements =
179           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
180      numLockConflicts = ASN1Integer.decodeAsInteger(elements[0]).intValue();
181      backendLockAcquired =
182           ASN1Boolean.decodeAsBoolean(elements[1]).booleanValue();
183    }
184    catch (final Exception e)
185    {
186      Debug.debugException(e);
187      throw new LDAPException(ResultCode.DECODING_ERROR,
188           ERR_TXN_SETTINGS_RESPONSE_ERROR_DECODING_VALUE.get(
189                StaticUtils.getExceptionMessage(e)));
190    }
191  }
192
193
194
195  /**
196   * Creates an encoded control value with the provided information.
197   *
198   * @param  numLockConflicts     The number of lock conflicts encountered
199   *                              during the course of processing the operation.
200   * @param  backendLockAcquired  Indicates whether the exclusive backend lock
201   *                              was acquired at any point during the course of
202   *                              processing the operation.
203   *
204   * @return  An encoded control value with the provided information.
205   */
206  private static ASN1OctetString encodeValue(final int numLockConflicts,
207                                             final boolean backendLockAcquired)
208  {
209    final ASN1Sequence valueSequence = new ASN1Sequence(
210         new ASN1Integer(TYPE_NUM_LOCK_CONFLICTS, numLockConflicts),
211         new ASN1Boolean(TYPE_BACKEND_LOCK_ACQUIRED, backendLockAcquired));
212    return new ASN1OctetString(valueSequence.encode());
213  }
214
215
216
217  /**
218   * {@inheritDoc}
219   */
220  @Override()
221  public TransactionSettingsResponseControl decodeControl(final String oid,
222                                                 final boolean isCritical,
223                                                 final ASN1OctetString value)
224         throws LDAPException
225  {
226    return new TransactionSettingsResponseControl(oid, isCritical, value);
227  }
228
229
230
231  /**
232   * Retrieves the number of lock conflicts encountered during the course of
233   * processing the associated operation.
234   *
235   * @return  The number of lock conflicts encountered during the course of
236   *          processing the associated operation.
237   */
238  public int getNumLockConflicts()
239  {
240    return numLockConflicts;
241  }
242
243
244
245  /**
246   * Indicates whether the exclusive backend lock was acquired at any point
247   * during the course of processing the associated operation.
248   *
249   * @return  {@code true} if the backend lock was acquired, or {@code false} if
250   *          not.
251   */
252  public boolean backendLockAcquired()
253  {
254    return backendLockAcquired;
255  }
256
257
258
259  /**
260   * Extracts a transaction settings response control from the provided extended
261   * result.
262   *
263   * @param  extendedResult  The extended result from which to retrieve the
264   *                         transaction settings response control.
265   *
266   * @return  The transaction settings response control contained in the
267   *          provided extended result, or {@code null} if the result did not
268   *          contain a transaction settings response control.
269   *
270   * @throws  LDAPException  If a problem is encountered while attempting to
271   *                         decode the transaction settings response control
272   *                         contained in the provided result.
273   */
274  public static TransactionSettingsResponseControl
275                     get(final ExtendedResult extendedResult)
276         throws LDAPException
277  {
278    final Control c =
279         extendedResult.getResponseControl(TRANSACTION_SETTINGS_RESPONSE_OID);
280    if (c == null)
281    {
282      return null;
283    }
284
285    if (c instanceof TransactionSettingsResponseControl)
286    {
287      return (TransactionSettingsResponseControl) c;
288    }
289    else
290    {
291      return new TransactionSettingsResponseControl(c.getOID(), c.isCritical(),
292           c.getValue());
293    }
294  }
295
296
297
298  /**
299   * {@inheritDoc}
300   */
301  @Override()
302  public String getControlName()
303  {
304    return INFO_CONTROL_NAME_TXN_SETTINGS_RESPONSE.get();
305  }
306
307
308
309  /**
310   * {@inheritDoc}
311   */
312  @Override()
313  public void toString(final StringBuilder buffer)
314  {
315    buffer.append("TransactionSettingsResponseControl(numLockConflicts=");
316    buffer.append(numLockConflicts);
317    buffer.append(", backendLockAcquired=");
318    buffer.append(backendLockAcquired);
319    buffer.append(')');
320  }
321}