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 }