001/*
002 * Copyright 2007-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2007-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) 2007-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.extensions;
037
038
039
040import com.unboundid.asn1.ASN1Boolean;
041import com.unboundid.asn1.ASN1Element;
042import com.unboundid.asn1.ASN1OctetString;
043import com.unboundid.asn1.ASN1Sequence;
044import com.unboundid.ldap.sdk.Control;
045import com.unboundid.ldap.sdk.ExtendedRequest;
046import com.unboundid.ldap.sdk.ExtendedResult;
047import com.unboundid.ldap.sdk.LDAPConnection;
048import com.unboundid.ldap.sdk.LDAPException;
049import com.unboundid.ldap.sdk.ResultCode;
050import com.unboundid.util.Debug;
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;
057
058import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
059
060
061
062/**
063 * This class provides an implementation of the end batched transaction extended
064 * request.  It may be used to either commit or abort a transaction that was
065 * created using the start batched transaction request.  See the documentation
066 * for the {@link StartBatchedTransactionExtendedRequest} for an example of
067 * processing a batched transaction.
068 * <BR>
069 * <BLOCKQUOTE>
070 *   <B>NOTE:</B>  This class, and other classes within the
071 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
072 *   supported for use against Ping Identity, UnboundID, and
073 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
074 *   for proprietary functionality or for external specifications that are not
075 *   considered stable or mature enough to be guaranteed to work in an
076 *   interoperable way with other types of LDAP servers.
077 * </BLOCKQUOTE>
078 */
079@NotMutable()
080@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
081public final class EndBatchedTransactionExtendedRequest
082       extends ExtendedRequest
083{
084  /**
085   * The OID (1.3.6.1.4.1.30221.2.6.2) for the end batched transaction extended
086   * request.
087   */
088  @NotNull public static final String END_BATCHED_TRANSACTION_REQUEST_OID =
089       "1.3.6.1.4.1.30221.2.6.2";
090
091
092
093  /**
094   * The serial version UID for this serializable class.
095   */
096  private static final long serialVersionUID = -8569129721687583552L;
097
098
099
100  // The transaction ID for the associated transaction.
101  @NotNull private final ASN1OctetString transactionID;
102
103  // Indicates whether to commit or abort the associated transaction.
104  private final boolean commit;
105
106
107
108  /**
109   * Creates a new end batched transaction extended request with the provided
110   * information.
111   *
112   * @param  transactionID  The transaction ID for the transaction to commit or
113   *                        abort.  It must not be {@code null}.
114   * @param  commit         {@code true} if the transaction should be committed,
115   *                        or {@code false} if the transaction should be
116   *                        aborted.
117   */
118  public EndBatchedTransactionExtendedRequest(
119              @NotNull final ASN1OctetString transactionID,
120              final boolean commit)
121  {
122    this(transactionID, commit, null);
123  }
124
125
126
127  /**
128   * Creates a new end batched transaction extended request with the provided
129   * information.
130   *
131   * @param  transactionID  The transaction ID for the transaction to commit or
132   *                        abort.  It must not be {@code null}.
133   * @param  commit         {@code true} if the transaction should be committed,
134   *                        or {@code false} if the transaction should be
135   *                        aborted.
136   * @param  controls       The set of controls to include in the request.
137   */
138  public EndBatchedTransactionExtendedRequest(
139              @NotNull final ASN1OctetString transactionID,
140              final boolean commit,
141              @Nullable final Control[] controls)
142  {
143    super(END_BATCHED_TRANSACTION_REQUEST_OID,
144          encodeValue(transactionID, commit),
145          controls);
146
147    this.transactionID = transactionID;
148    this.commit        = commit;
149  }
150
151
152
153  /**
154   * Creates a new end batched transaction extended request from the provided
155   * generic extended request.
156   *
157   * @param  extendedRequest  The generic extended request to use to create this
158   *                          end batched transaction extended request.
159   *
160   * @throws  LDAPException  If a problem occurs while decoding the request.
161   */
162  public EndBatchedTransactionExtendedRequest(
163              @NotNull final ExtendedRequest extendedRequest)
164         throws LDAPException
165  {
166    super(extendedRequest);
167
168    final ASN1OctetString value = extendedRequest.getValue();
169    if (value == null)
170    {
171      throw new LDAPException(ResultCode.DECODING_ERROR,
172                              ERR_END_TXN_REQUEST_NO_VALUE.get());
173    }
174
175    try
176    {
177      final ASN1Element valueElement = ASN1Element.decode(value.getValue());
178      final ASN1Element[] elements =
179           ASN1Sequence.decodeAsSequence(valueElement).elements();
180      if (elements.length == 1)
181      {
182        commit        = true;
183        transactionID = ASN1OctetString.decodeAsOctetString(elements[0]);
184      }
185      else
186      {
187        commit        = ASN1Boolean.decodeAsBoolean(elements[0]).booleanValue();
188        transactionID = ASN1OctetString.decodeAsOctetString(elements[1]);
189      }
190    }
191    catch (final Exception e)
192    {
193      Debug.debugException(e);
194      throw new LDAPException(ResultCode.DECODING_ERROR,
195                              ERR_END_TXN_REQUEST_CANNOT_DECODE.get(e), e);
196    }
197  }
198
199
200
201  /**
202   * Generates the value to include in this extended request.
203   *
204   * @param  transactionID  The transaction ID for the transaction to commit or
205   *                        abort.  It must not be {@code null}.
206   * @param  commit         {@code true} if the transaction should be committed,
207   *                        or {@code false} if the transaction should be
208   *                        aborted.
209   *
210   * @return  The ASN.1 octet string containing the encoded request value.
211   */
212  @NotNull()
213  private static ASN1OctetString encodeValue(
214               @NotNull final ASN1OctetString transactionID,
215               final boolean commit)
216  {
217    Validator.ensureNotNull(transactionID);
218
219    final ASN1Element[] valueElements;
220    if (commit)
221    {
222      valueElements = new ASN1Element[]
223      {
224        transactionID
225      };
226    }
227    else
228    {
229      valueElements = new ASN1Element[]
230      {
231        new ASN1Boolean(commit),
232        transactionID
233      };
234    }
235
236    return new ASN1OctetString(new ASN1Sequence(valueElements).encode());
237  }
238
239
240
241  /**
242   * Retrieves the transaction ID for the transaction to commit or abort.
243   *
244   * @return  The transaction ID for the transaction to commit or abort.
245   */
246  @NotNull()
247  public ASN1OctetString getTransactionID()
248  {
249    return transactionID;
250  }
251
252
253
254  /**
255   * Indicates whether the transaction should be committed or aborted.
256   *
257   * @return  {@code true} if the transaction should be committed, or
258   *          {@code false} if it should be aborted.
259   */
260  public boolean commit()
261  {
262    return commit;
263  }
264
265
266
267  /**
268   * {@inheritDoc}
269   */
270  @Override()
271  @NotNull()
272  public EndBatchedTransactionExtendedResult process(
273              @NotNull final LDAPConnection connection, final int depth)
274         throws LDAPException
275  {
276    final ExtendedResult extendedResponse = super.process(connection, depth);
277    return new EndBatchedTransactionExtendedResult(extendedResponse);
278  }
279
280
281
282  /**
283   * {@inheritDoc}
284   */
285  @Override()
286  @NotNull()
287  public EndBatchedTransactionExtendedRequest duplicate()
288  {
289    return duplicate(getControls());
290  }
291
292
293
294  /**
295   * {@inheritDoc}
296   */
297  @Override()
298  @NotNull()
299  public EndBatchedTransactionExtendedRequest duplicate(
300              @Nullable final Control[] controls)
301  {
302    final EndBatchedTransactionExtendedRequest r =
303         new EndBatchedTransactionExtendedRequest(transactionID, commit,
304              controls);
305    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
306    r.setIntermediateResponseListener(getIntermediateResponseListener());
307    r.setReferralDepth(getReferralDepth());
308    r.setReferralConnector(getReferralConnectorInternal());
309    return r;
310  }
311
312
313
314  /**
315   * {@inheritDoc}
316   */
317  @Override()
318  @NotNull()
319  public String getExtendedRequestName()
320  {
321    return INFO_EXTENDED_REQUEST_NAME_END_BATCHED_TXN.get();
322  }
323
324
325
326  /**
327   * {@inheritDoc}
328   */
329  @Override()
330  public void toString(@NotNull final StringBuilder buffer)
331  {
332    buffer.append("EndBatchedTransactionExtendedRequest(transactionID='");
333    buffer.append(transactionID.stringValue());
334    buffer.append("', commit=");
335    buffer.append(commit);
336
337    final Control[] controls = getControls();
338    if (controls.length > 0)
339    {
340      buffer.append("controls={");
341      for (int i=0; i < controls.length; i++)
342      {
343        if (i > 0)
344        {
345          buffer.append(", ");
346        }
347
348        buffer.append(controls[i]);
349      }
350      buffer.append('}');
351    }
352
353    buffer.append(')');
354  }
355}