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