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