001/* 002 * Copyright 2014-2025 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2014-2025 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) 2014-2025 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.controls; 037 038 039 040import java.util.ArrayList; 041 042import com.unboundid.asn1.ASN1Boolean; 043import com.unboundid.asn1.ASN1Element; 044import com.unboundid.asn1.ASN1Enumerated; 045import com.unboundid.asn1.ASN1Integer; 046import com.unboundid.asn1.ASN1Long; 047import com.unboundid.asn1.ASN1OctetString; 048import com.unboundid.asn1.ASN1Sequence; 049import com.unboundid.ldap.sdk.Control; 050import com.unboundid.ldap.sdk.LDAPException; 051import com.unboundid.ldap.sdk.ResultCode; 052import com.unboundid.util.Debug; 053import com.unboundid.util.NotMutable; 054import com.unboundid.util.NotNull; 055import com.unboundid.util.Nullable; 056import com.unboundid.util.StaticUtils; 057import com.unboundid.util.ThreadSafety; 058import com.unboundid.util.ThreadSafetyLevel; 059import com.unboundid.util.Validator; 060 061import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 062 063 064 065/** 066 * This class provides a request control that can be used to specify a number of 067 * settings used for any database transaction that may be associated with the 068 * associated request. It may be included in an end transaction extended 069 * request or an atomic multi-update extended request (it is not supported for 070 * use in non-atomic multi-update requests). 071 * <BR> 072 * <BLOCKQUOTE> 073 * <B>NOTE:</B> This class, and other classes within the 074 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 075 * supported for use against Ping Identity, UnboundID, and 076 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 077 * for proprietary functionality or for external specifications that are not 078 * considered stable or mature enough to be guaranteed to work in an 079 * interoperable way with other types of LDAP servers. 080 * </BLOCKQUOTE> 081 * <BR> 082 * This control has an OID of 1.3.6.1.4.1.30221.2.5.38. It may have a 083 * criticality of either {@code true} (in which case the server will reject the 084 * associated operation if this control is not recognized) or {@code false} (in 085 * which case the server will ignore this control if it is not recognized). It 086 * must have a value with the following encoding: 087 * <PRE> 088 * TransactionSettingsRequestValue ::= SEQUENCE { 089 * transactionName [0] OCTET STRING OPTIONAL, 090 * commitDurability [1] ENUMERATED { 091 * nonSynchronous (0), 092 * partiallySynchronous (1), 093 * fullySynchronous (2), 094 * ... } OPTIONAL, 095 * backendLockBehavior [2] ENUMERATED { 096 * doNotAcquire (0), 097 * acquireAfterRetries (1), 098 * acquireBeforeRetries (2), 099 * acquireBeforeInitialAttempt (3), 100 * ... } OPTIONAL, 101 * backendLockTimeoutMillis [3] INTEGER OPTIONAL, 102 * retryAttempts [4] INTEGER OPTIONAL, 103 * txnLockTimeout [5] SEQUENCE { 104 * minTimeoutMillis INTEGER, 105 * maxTimeoutMillis INTEGER, 106 * ... } OPTIONAL, 107 * returnResponseControl [6] BOOLEAN DEFAULT FALSE, 108 * singleWriterLockBehavior [7] ENUMERATED { 109 * doNotAcquire (0), 110 * acquireAfterRetries (1), 111 * acquireBeforeRetries (2), 112 * acquireBeforeInitialAttempt (3), 113 * ... } OPTIONAL, 114 * scopedLockDetails [8] SEQUENCE { 115 * scopeIdentifier [9] OCTET STRING, 116 * lockBehavior [10] ENUMERATED { 117 * doNotAcquire (0), 118 * acquireAfterRetries (1), 119 * acquireBeforeRetries (2), 120 * acquireBeforeInitialAttempt (3), 121 * ... }, 122 * ... } OPTIONAL, 123 * returnResponseControl [11] BOOLEAN DEFAULT FALSE, 124 * ... } 125 * </PRE> 126 */ 127@NotMutable() 128@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 129public final class TransactionSettingsRequestControl 130 extends Control 131{ 132 /** 133 * The OID (1.3.6.1.4.1.30221.2.5.38) for the undelete request control. 134 */ 135 @NotNull public static final String TRANSACTION_SETTINGS_REQUEST_OID = 136 "1.3.6.1.4.1.30221.2.5.38"; 137 138 139 140 /** 141 * The BER type for the value sequence element that specifies the name to use 142 * for the transaction. 143 */ 144 private static final byte TYPE_TXN_NAME = (byte) 0x80; 145 146 147 148 /** 149 * The BER type for the value sequence element that specifies the commit 150 * durability to use. 151 */ 152 private static final byte TYPE_COMMIT_DURABILITY = (byte) 0x81; 153 154 155 156 /** 157 * The BER type for the value sequence element that specifies the behavior 158 * to use with regard to acquiring the backend exclusive lock. 159 */ 160 private static final byte TYPE_BACKEND_EXCLUSIVE_LOCK_BEHAVIOR = (byte) 0x82; 161 162 163 164 /** 165 * The BER type for the value sequence element that specifies the exclusive 166 * backend lock timeout. 167 */ 168 private static final byte TYPE_BACKEND_LOCK_TIMEOUT = (byte) 0x83; 169 170 171 172 /** 173 * The BER type for the value sequence element that specifies the number of 174 * retry attempts. 175 */ 176 private static final byte TYPE_RETRY_ATTEMPTS = (byte) 0x84; 177 178 179 180 /** 181 * The BER type for the value sequence element that specifies the minimum and 182 * maximum database lock timeout values. 183 */ 184 private static final byte TYPE_TXN_LOCK_TIMEOUT = (byte) 0xA5; 185 186 187 188 /** 189 * The BER type for the value sequence element that indicates whether the 190 * contents of the control should be considered when the operation is 191 * replciated to other servers in the topology. 192 */ 193 private static final byte TYPE_REPLICATE_CONTROL = (byte) 0x8B; 194 195 196 197 /** 198 * The BER type for the value sequence element that indicates whether to 199 * return a response control with transaction-related information about the 200 * processing of the associated operation. 201 */ 202 private static final byte TYPE_RETURN_RESPONSE_CONTROL = (byte) 0x86; 203 204 205 206 /** 207 * The BER type for the value sequence element that specifies the behavior 208 * to use with regard to acquiring the backend single-writer lock. 209 */ 210 private static final byte TYPE_SINGLE_WRITER_LOCK_BEHAVIOR = (byte) 0x87; 211 212 213 214 /** 215 * The BER type for the value sequence element that encapsulates information 216 * about the potential need to acquire a scoped lock during operation 217 * processing. 218 */ 219 static final byte TYPE_SCOPED_LOCK_DETAILS = (byte) 0xA8; 220 221 222 223 /** 224 * The serial version UID for this serializable class. 225 */ 226 private static final long serialVersionUID = -4749344077745581287L; 227 228 229 230 // Indicates whether the settings in this control should be considered when 231 // the operation is replicated to other servers in the topology. 232 private final boolean replicateControl; 233 234 // Indicates whether to return a response control. 235 private final boolean returnResponseControl; 236 237 // The number of times to retry if a lock conflict exception is encountered. 238 @Nullable private final Integer retryAttempts; 239 240 // The backend lock timeout, in milliseconds. 241 @Nullable private final Long backendLockTimeoutMillis; 242 243 // The maximum transaction lock timeout, in milliseconds. 244 @Nullable private final Long maxTxnLockTimeoutMillis; 245 246 // The minimum transaction lock timeout, in milliseconds. 247 @Nullable private final Long minTxnLockTimeoutMillis; 248 249 // The requested transaction name. 250 @Nullable private final String transactionName; 251 252 // The behavior to use with regard to requesting the backend exclusive lock. 253 @Nullable private final TransactionSettingsBackendLockBehavior 254 backendExclusiveLockBehavior; 255 256 // The behavior to use with regard to requesting the single-writer backend 257 // lock. 258 @Nullable private final TransactionSettingsBackendLockBehavior 259 singleWriterLockBehavior; 260 261 // The requested commit durability setting. 262 @Nullable private final TransactionSettingsCommitDurability commitDurability; 263 264 // Details about scoped lock usage. 265 @Nullable private final TransactionSettingsScopedLockDetails 266 scopedLockDetails; 267 268 269 270 /** 271 * Creates a new transaction settings request control with the provided 272 * information. 273 * 274 * @param isCritical Indicates whether the control should be 275 * considered critical. 276 * @param transactionName The name to use for the transaction. It 277 * may be {@code null} if no 278 * client-specified transaction name is 279 * needed. If a transaction name is 280 * provided, it will be used purely for 281 * informational and/or troubleshooting 282 * purposes. 283 * @param commitDurability The durability level that should be used 284 * when committing the associated 285 * transaction. It may be {@code null} if 286 * the server-default durability level 287 * should be used. 288 * @param backendLockBehavior The behavior that should be used with 289 * regard to acquiring an exclusive lock for 290 * processing in the target backend. It may 291 * be {@code null} if the server-default 292 * backend lock behavior should be used. 293 * @param backendLockTimeoutMillis The maximum length of time in 294 * milliseconds to spend attempting to 295 * acquire an exclusive backend lock if it 296 * is needed during any part of the 297 * processing. A value that of zero 298 * indicates that no timeout should be 299 * enforced. It may be {@code null} if the 300 * server will determine the backend lock 301 * timeout that should be used. 302 * @param retryAttempts The number of times to retry the 303 * associated operations in a new 304 * transaction if the initial attempt fails. 305 * If this is {@code null}, then the server 306 * will determine the number of retry 307 * attempts to make. Note that depending on 308 * the backend lock behavior, the server may 309 * make one additional retry attempt if 310 * necessary after acquiring an exclusive 311 * backend lock. 312 * @param minTxnLockTimeoutMillis The minimum database lock timeout that 313 * should be used for the associated 314 * transaction. If this is specified, then 315 * the first attempt will use this lock 316 * timeout, and subsequent attempts will use 317 * a timeout value between this and the 318 * maximum database lock timeout (which must 319 * also be specified). If this is 320 * {@code null}, then the server will 321 * determine the database lock timeout 322 * settings to use. 323 * @param maxTxnLockTimeoutMillis The maximum database lock timeout that 324 * should be used for the associated 325 * transaction. If this is specified, then 326 * the minimum database lock timeout must 327 * also be specified, and this value must be 328 * greater than or equal to the minimum lock 329 * timeout. If this is {@code null}, then 330 * the server will determine the database 331 * lock timeout settings to use. 332 */ 333 public TransactionSettingsRequestControl(final boolean isCritical, 334 @Nullable final String transactionName, 335 @Nullable final TransactionSettingsCommitDurability commitDurability, 336 @Nullable final TransactionSettingsBackendLockBehavior 337 backendLockBehavior, 338 @Nullable final Long backendLockTimeoutMillis, 339 @Nullable final Integer retryAttempts, 340 @Nullable final Long minTxnLockTimeoutMillis, 341 @Nullable final Long maxTxnLockTimeoutMillis) 342 { 343 this(isCritical, transactionName, commitDurability, backendLockBehavior, 344 backendLockTimeoutMillis, retryAttempts, minTxnLockTimeoutMillis, 345 maxTxnLockTimeoutMillis, false); 346 } 347 348 349 350 /** 351 * Creates a new transaction settings request control with the provided 352 * information. 353 * 354 * @param isCritical Indicates whether the control should be 355 * considered critical. 356 * @param transactionName The name to use for the transaction. It 357 * may be {@code null} if no 358 * client-specified transaction name is 359 * needed. If a transaction name is 360 * provided, it will be used purely for 361 * informational and/or troubleshooting 362 * purposes. 363 * @param commitDurability The durability level that should be used 364 * when committing the associated 365 * transaction. It may be {@code null} if 366 * the server-default durability level 367 * should be used. 368 * @param backendLockBehavior The behavior that should be used with 369 * regard to acquiring an exclusive lock for 370 * processing in the target backend. It may 371 * be {@code null} if the server-default 372 * backend lock behavior should be used. 373 * @param backendLockTimeoutMillis The maximum length of time in 374 * milliseconds to spend attempting to 375 * acquire an exclusive backend lock if it 376 * is needed during any part of the 377 * processing. A value that of zero 378 * indicates that no timeout should be 379 * enforced. It may be {@code null} if the 380 * server will determine the backend lock 381 * timeout that should be used. 382 * @param retryAttempts The number of times to retry the 383 * associated operations in a new 384 * transaction if the initial attempt fails. 385 * If this is {@code null}, then the server 386 * will determine the number of retry 387 * attempts to make. Note that depending on 388 * the backend lock behavior, the server may 389 * make one additional retry attempt if 390 * necessary after acquiring an exclusive 391 * backend lock. 392 * @param minTxnLockTimeoutMillis The minimum database lock timeout that 393 * should be used for the associated 394 * transaction. If this is specified, then 395 * the first attempt will use this lock 396 * timeout, and subsequent attempts will use 397 * a timeout value between this and the 398 * maximum database lock timeout (which must 399 * also be specified). If this is 400 * {@code null}, then the server will 401 * determine the database lock timeout 402 * settings to use. 403 * @param maxTxnLockTimeoutMillis The maximum database lock timeout that 404 * should be used for the associated 405 * transaction. If this is specified, then 406 * the minimum database lock timeout must 407 * also be specified, and this value must be 408 * greater than or equal to the minimum lock 409 * timeout. If this is {@code null}, then 410 * the server will determine the database 411 * lock timeout settings to use. 412 * @param returnResponseControl Indicates whether to return a response 413 * control with transaction-related 414 * information collected over the course of 415 * processing the associated operation. 416 */ 417 public TransactionSettingsRequestControl(final boolean isCritical, 418 @Nullable final String transactionName, 419 @Nullable final TransactionSettingsCommitDurability commitDurability, 420 @Nullable final TransactionSettingsBackendLockBehavior 421 backendLockBehavior, 422 @Nullable final Long backendLockTimeoutMillis, 423 @Nullable final Integer retryAttempts, 424 @Nullable final Long minTxnLockTimeoutMillis, 425 @Nullable final Long maxTxnLockTimeoutMillis, 426 final boolean returnResponseControl) 427 { 428 super(TRANSACTION_SETTINGS_REQUEST_OID, isCritical, 429 encodeValue(transactionName, commitDurability, backendLockBehavior, 430 null, null, backendLockTimeoutMillis, retryAttempts, 431 minTxnLockTimeoutMillis, maxTxnLockTimeoutMillis, false, 432 returnResponseControl)); 433 434 this.transactionName = transactionName; 435 this.commitDurability = commitDurability; 436 this.backendExclusiveLockBehavior = backendLockBehavior; 437 this.backendLockTimeoutMillis = backendLockTimeoutMillis; 438 this.minTxnLockTimeoutMillis = minTxnLockTimeoutMillis; 439 this.maxTxnLockTimeoutMillis = maxTxnLockTimeoutMillis; 440 this.retryAttempts = retryAttempts; 441 this.returnResponseControl = returnResponseControl; 442 443 singleWriterLockBehavior = null; 444 scopedLockDetails = null; 445 replicateControl = false; 446 } 447 448 449 450 /** 451 * Creates a new transaction settings request control with the provided 452 * information. 453 * 454 * @param isCritical Indicates whether the control should be considered 455 * critical. 456 * @param properties The properties to use for the request control. 457 */ 458 public TransactionSettingsRequestControl(final boolean isCritical, 459 @NotNull final TransactionSettingsReqeustControlProperties properties) 460 { 461 super(TRANSACTION_SETTINGS_REQUEST_OID, isCritical, 462 encodeValue(properties.getTransactionName(), 463 properties.getCommitDurability(), 464 properties.getBackendExclusiveLockBehavior(), 465 properties.getSingleWriterLockBehavior(), 466 properties.getScopedLockDetails(), 467 properties.getBackendLockTimeoutMillis(), 468 properties.getRetryAttempts(), 469 properties.getMinTxnLockTimeoutMillis(), 470 properties.getMaxTxnLockTimeoutMillis(), 471 properties.replicateControl(), 472 properties.getReturnResponseControl())); 473 474 transactionName = properties.getTransactionName(); 475 commitDurability = properties.getCommitDurability(); 476 backendExclusiveLockBehavior = properties.getBackendExclusiveLockBehavior(); 477 singleWriterLockBehavior = properties.getSingleWriterLockBehavior(); 478 scopedLockDetails = properties.getScopedLockDetails(); 479 backendLockTimeoutMillis = properties.getBackendLockTimeoutMillis(); 480 minTxnLockTimeoutMillis = properties.getMinTxnLockTimeoutMillis(); 481 maxTxnLockTimeoutMillis = properties.getMaxTxnLockTimeoutMillis(); 482 retryAttempts = properties.getRetryAttempts(); 483 replicateControl = properties.replicateControl(); 484 returnResponseControl = properties.getReturnResponseControl(); 485 } 486 487 488 489 /** 490 * Creates a new transaction settings request control that is decoded from the 491 * provided generic control. 492 * 493 * @param c The generic control to decode as a transaction settings request 494 * control. 495 * 496 * @throws LDAPException If a problem is encountered while attempting to 497 * decode the provided control as a transaction 498 * settings request control. 499 */ 500 public TransactionSettingsRequestControl(@NotNull final Control c) 501 throws LDAPException 502 { 503 super(c); 504 505 final ASN1OctetString value = c.getValue(); 506 if (value == null) 507 { 508 throw new LDAPException(ResultCode.DECODING_ERROR, 509 ERR_TXN_SETTINGS_REQUEST_MISSING_VALUE.get()); 510 } 511 512 try 513 { 514 boolean replicate = false; 515 boolean responseControl = false; 516 Integer numRetries = null; 517 Long backendTimeout = null; 518 Long maxTxnLockTimeout = null; 519 Long minTxnLockTimeout = null; 520 String txnName = null; 521 TransactionSettingsBackendLockBehavior exclusiveLockBehavior = null; 522 TransactionSettingsBackendLockBehavior swLockBehavior = null; 523 TransactionSettingsCommitDurability durability = null; 524 TransactionSettingsScopedLockDetails scopeDetails = null; 525 526 for (final ASN1Element e : 527 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 528 { 529 switch (e.getType()) 530 { 531 case TYPE_TXN_NAME: 532 txnName = ASN1OctetString.decodeAsOctetString(e).stringValue(); 533 break; 534 535 case TYPE_COMMIT_DURABILITY: 536 durability = TransactionSettingsCommitDurability.valueOf( 537 ASN1Enumerated.decodeAsEnumerated(e).intValue()); 538 if (durability == null) 539 { 540 throw new LDAPException(ResultCode.DECODING_ERROR, 541 ERR_TXN_SETTINGS_REQUEST_UNKNOWN_DURABILITY.get( 542 ASN1Enumerated.decodeAsEnumerated(e).intValue())); 543 } 544 break; 545 546 case TYPE_BACKEND_EXCLUSIVE_LOCK_BEHAVIOR: 547 exclusiveLockBehavior = 548 TransactionSettingsBackendLockBehavior.valueOf( 549 ASN1Enumerated.decodeAsEnumerated(e).intValue()); 550 if (exclusiveLockBehavior == null) 551 { 552 throw new LDAPException(ResultCode.DECODING_ERROR, 553 ERR_TXN_SETTINGS_REQUEST_UNKNOWN_EXCLUSIVE_LOCK_BEHAVIOR.get( 554 ASN1Enumerated.decodeAsEnumerated(e).intValue())); 555 } 556 break; 557 558 case TYPE_BACKEND_LOCK_TIMEOUT: 559 backendTimeout = ASN1Long.decodeAsLong(e).longValue(); 560 if (backendTimeout < 0L) 561 { 562 throw new LDAPException(ResultCode.DECODING_ERROR, 563 ERR_TXN_SETTINGS_REQUEST_INVALID_BACKEND_LOCK_TIMEOUT.get( 564 backendTimeout)); 565 } 566 break; 567 568 case TYPE_RETRY_ATTEMPTS: 569 numRetries = ASN1Integer.decodeAsInteger(e).intValue(); 570 if (numRetries < 0) 571 { 572 throw new LDAPException(ResultCode.DECODING_ERROR, 573 ERR_TXN_SETTINGS_REQUEST_INVALID_RETRY_ATTEMPTS.get( 574 numRetries)); 575 } 576 break; 577 578 case TYPE_TXN_LOCK_TIMEOUT: 579 final ASN1Element[] timeoutElements = 580 ASN1Sequence.decodeAsSequence(e).elements(); 581 minTxnLockTimeout = 582 ASN1Long.decodeAsLong(timeoutElements[0]).longValue(); 583 maxTxnLockTimeout = 584 ASN1Long.decodeAsLong(timeoutElements[1]).longValue(); 585 if (minTxnLockTimeout < 0) 586 { 587 throw new LDAPException(ResultCode.DECODING_ERROR, 588 ERR_TXN_SETTINGS_REQUEST_INVALID_MIN_TXN_LOCK_TIMEOUT.get( 589 minTxnLockTimeout)); 590 } 591 if (maxTxnLockTimeout < minTxnLockTimeout) 592 { 593 throw new LDAPException(ResultCode.DECODING_ERROR, 594 ERR_TXN_SETTINGS_REQUEST_INVALID_MAX_TXN_LOCK_TIMEOUT.get( 595 maxTxnLockTimeout, minTxnLockTimeout)); 596 } 597 break; 598 599 case TYPE_SINGLE_WRITER_LOCK_BEHAVIOR: 600 swLockBehavior = 601 TransactionSettingsBackendLockBehavior.valueOf( 602 ASN1Enumerated.decodeAsEnumerated(e).intValue()); 603 if (swLockBehavior == null) 604 { 605 throw new LDAPException(ResultCode.DECODING_ERROR, 606 ERR_TXN_SETTINGS_REQUEST_UNKNOWN_SW_LOCK_BEHAVIOR.get( 607 ASN1Enumerated.decodeAsEnumerated(e).intValue())); 608 } 609 break; 610 611 case TYPE_SCOPED_LOCK_DETAILS: 612 scopeDetails = TransactionSettingsScopedLockDetails.decode(e); 613 break; 614 615 case TYPE_REPLICATE_CONTROL: 616 replicate = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 617 break; 618 619 case TYPE_RETURN_RESPONSE_CONTROL: 620 responseControl = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 621 break; 622 623 default: 624 throw new LDAPException(ResultCode.DECODING_ERROR, 625 ERR_TXN_SETTINGS_REQUEST_UNRECOGNIZED_ELEMENT_TYPE.get( 626 StaticUtils.toHex(e.getType()))); 627 } 628 } 629 630 transactionName = txnName; 631 commitDurability = durability; 632 backendExclusiveLockBehavior = exclusiveLockBehavior; 633 singleWriterLockBehavior = swLockBehavior; 634 scopedLockDetails = scopeDetails; 635 backendLockTimeoutMillis = backendTimeout; 636 minTxnLockTimeoutMillis = minTxnLockTimeout; 637 maxTxnLockTimeoutMillis = maxTxnLockTimeout; 638 retryAttempts = numRetries; 639 replicateControl = replicate; 640 returnResponseControl = responseControl; 641 } 642 catch (final LDAPException le) 643 { 644 Debug.debugException(le); 645 throw le; 646 } 647 catch (final Exception e) 648 { 649 Debug.debugException(e); 650 throw new LDAPException(ResultCode.DECODING_ERROR, 651 ERR_TXN_SETTINGS_REQUEST_ERROR_DECODING_VALUE.get( 652 StaticUtils.getExceptionMessage(e)), 653 e); 654 } 655 } 656 657 658 659 /** 660 * Encodes the provided information into a form suitable for use as the value 661 * of this ASN.1 element. 662 * 663 * @param transactionName The name to use for the transaction. It 664 * may be {@code null} if no 665 * client-specified transaction name is 666 * needed. If a transaction name is 667 * provided, it will be used purely for 668 * informational and/or troubleshooting 669 * purposes. 670 * @param commitDurability The durability level that should be used 671 * when committing the associated 672 * transaction. It may be {@code null} if 673 * the server-default durability level 674 * should be used. 675 * @param backendLockBehavior The behavior that should be used with 676 * regard to acquiring an exclusive lock for 677 * processing in the target backend. It may 678 * be {@code null} if the server-default 679 * backend exclusive lock behavior should be 680 * used. 681 * @param singleWriterLockBehavior The behavior that should be used with 682 * regard to acquiring a single-writer lock 683 * for processing in the target backend. It 684 * may be {@code null} if the server-default 685 * single-writer lock behavior should be 686 * used. 687 * @param scopedLockDetails Details about the conditions under which 688 * the server should attempt to acquire a 689 * scoped lock. It may be {@code null} if 690 * no attempt should be made to acquire a 691 * scoped lock. 692 * @param backendLockTimeoutMillis The maximum length of time in 693 * milliseconds to spend attempting to 694 * acquire an exclusive backend lock if it 695 * is needed during any part of the 696 * processing. A value that of zero 697 * indicates that no timeout should be 698 * enforced. It may be {@code null} if the 699 * server will determine the backend lock 700 * timeout that should be used. 701 * @param retryAttempts The number of times to retry the 702 * associated operations in a new 703 * transaction if the initial attempt fails. 704 * If this is {@code null}, then the server 705 * will determine the number of retry 706 * attempts to make. Note that depending on 707 * the backend lock behavior, the server may 708 * make one additional retry attempt if 709 * necessary after acquiring an exclusive 710 * backend lock. 711 * @param minTxnLockTimeoutMillis The minimum database lock timeout that 712 * should be used for the associated 713 * transaction. If this is specified, then 714 * the first attempt will use this lock 715 * timeout, and subsequent attempts will use 716 * a timeout value between this and the 717 * maximum database lock timeout (which must 718 * also be specified). If this is 719 * {@code null}, then the server will 720 * determine the database lock timeout 721 * settings to use. 722 * @param maxTxnLockTimeoutMillis The maximum database lock timeout that 723 * should be used for the associated 724 * transaction. If this is specified, then 725 * the minimum database lock timeout must 726 * also be specified, and this value must be 727 * greater than or equal to the minimum lock 728 * timeout. If this is {@code null}, then 729 * the server will determine the database 730 * lock timeout settings to use. 731 * @param replicateControl Indicates whether the settings in this 732 * control should be considered when the 733 * operation is replicated to other servers 734 * in the topology. 735 * @param returnResponseControl Indicates whether to return a response 736 * control with transaction-related 737 * information collected over the course of 738 * processing the associated operation. 739 * 740 * @return The encoded value to use for the control. 741 */ 742 @NotNull() 743 private static ASN1OctetString encodeValue( 744 @Nullable final String transactionName, 745 @Nullable final TransactionSettingsCommitDurability commitDurability, 746 @Nullable final TransactionSettingsBackendLockBehavior 747 backendLockBehavior, 748 @Nullable final TransactionSettingsBackendLockBehavior 749 singleWriterLockBehavior, 750 @Nullable final TransactionSettingsScopedLockDetails scopedLockDetails, 751 @Nullable final Long backendLockTimeoutMillis, 752 @Nullable final Integer retryAttempts, 753 @Nullable final Long minTxnLockTimeoutMillis, 754 @Nullable final Long maxTxnLockTimeoutMillis, 755 final boolean replicateControl, 756 final boolean returnResponseControl) 757 { 758 final ArrayList<ASN1Element> elements = new ArrayList<>(10); 759 760 if (transactionName != null) 761 { 762 elements.add(new ASN1OctetString(TYPE_TXN_NAME, transactionName)); 763 } 764 765 if (commitDurability != null) 766 { 767 elements.add(new ASN1Enumerated(TYPE_COMMIT_DURABILITY, 768 commitDurability.intValue())); 769 } 770 771 if (backendLockBehavior != null) 772 { 773 elements.add(new ASN1Enumerated(TYPE_BACKEND_EXCLUSIVE_LOCK_BEHAVIOR, 774 backendLockBehavior.intValue())); 775 } 776 777 if (backendLockTimeoutMillis != null) 778 { 779 Validator.ensureTrue((backendLockTimeoutMillis >= 0L), 780 "If a backend lock timeout is specified, then it must be greater " + 781 "than or equal to zero."); 782 elements.add(new ASN1Long(TYPE_BACKEND_LOCK_TIMEOUT, 783 backendLockTimeoutMillis)); 784 } 785 786 if (retryAttempts != null) 787 { 788 Validator.ensureTrue((retryAttempts >= 0), 789 "If specified, the number of retry attempts must be greater than " + 790 "or equal to zero."); 791 792 elements.add(new ASN1Integer(TYPE_RETRY_ATTEMPTS, retryAttempts)); 793 } 794 795 if (minTxnLockTimeoutMillis != null) 796 { 797 Validator.ensureTrue((maxTxnLockTimeoutMillis != null), 798 "If a minimum transaction lock timeout is specified, then a " + 799 "maximum transaction lock timeout must also be specified."); 800 Validator.ensureTrue((minTxnLockTimeoutMillis > 0), 801 "If a minimum transaction lock timeout is specified, then it must " + 802 "be greater than zero."); 803 Validator.ensureTrue((maxTxnLockTimeoutMillis >= minTxnLockTimeoutMillis), 804 "If a minimum transaction lock timeout is specified, then it must " + 805 "be less than or equal to the minimum transaction lock " + 806 "timeout."); 807 elements.add(new ASN1Sequence(TYPE_TXN_LOCK_TIMEOUT, 808 new ASN1Long(minTxnLockTimeoutMillis), 809 new ASN1Long(maxTxnLockTimeoutMillis))); 810 } 811 else 812 { 813 Validator.ensureTrue((maxTxnLockTimeoutMillis == null), 814 "If a maximum transaction lock timeout is specified, then a " + 815 "minimum transaction lock timeout must also be specified."); 816 } 817 818 if (returnResponseControl) 819 { 820 elements.add(new ASN1Boolean(TYPE_RETURN_RESPONSE_CONTROL, true)); 821 } 822 823 if (singleWriterLockBehavior != null) 824 { 825 elements.add(new ASN1Enumerated(TYPE_SINGLE_WRITER_LOCK_BEHAVIOR, 826 singleWriterLockBehavior.intValue())); 827 } 828 829 if (scopedLockDetails != null) 830 { 831 final ASN1Element scopedLockDetailsElement = 832 scopedLockDetails.encode(); 833 if (scopedLockDetailsElement != null) 834 { 835 elements.add(scopedLockDetailsElement); 836 } 837 } 838 839 if (replicateControl) 840 { 841 elements.add(new ASN1Boolean(TYPE_REPLICATE_CONTROL, true)); 842 } 843 844 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 845 } 846 847 848 849 /** 850 * Retrieves the name to assign to the associated transaction, if specified. 851 * 852 * @return The name to assign to the associated transaction, or {@code null} 853 * if none has been specified. 854 */ 855 @Nullable() 856 public String getTransactionName() 857 { 858 return transactionName; 859 } 860 861 862 863 /** 864 * Retrieves the commit durability that should be used for the associated 865 * transaction, if specified. 866 * 867 * @return The commit durability that should be used for the associated 868 * transaction, or {@code null} if none has been specified and the 869 * server should determine the commit durability. 870 */ 871 @Nullable() 872 public TransactionSettingsCommitDurability getCommitDurability() 873 { 874 return commitDurability; 875 } 876 877 878 879 /** 880 * Retrieves the backend exclusive lock behavior that should be used for the 881 * associated transaction, if specified. 882 * 883 * @return The backend exclusive lock behavior that should be used for the 884 * associated transaction, or {@code null} if none has been specified 885 * and the server should determine the backend exclusive lock 886 * behavior. 887 */ 888 @Nullable() 889 public TransactionSettingsBackendLockBehavior getBackendLockBehavior() 890 { 891 return backendExclusiveLockBehavior; 892 } 893 894 895 896 /** 897 * Retrieves the single-wwriter lock behavior that should be used for the 898 * associated transaction, if specified. 899 * 900 * @return The single-writer lock behavior that should be used for the 901 * associated transaction, or {@code null} if none has been specified 902 * and the server should determine the backend exclusive lock 903 * behavior. 904 */ 905 @Nullable() 906 public TransactionSettingsBackendLockBehavior getSingleWriterLockBehavior() 907 { 908 return singleWriterLockBehavior; 909 } 910 911 912 913 /** 914 * Retrieves details about the conditions under which the server should 915 * attempt to acquire a scoped lock. 916 * 917 * @return Details about the conditions under which the server should attempt 918 * to acquire a scoped lock, or {@code null} if no attempt should be 919 * made to acquire a scoped lock. 920 */ 921 @Nullable() 922 public TransactionSettingsScopedLockDetails getScopedLockDetails() 923 { 924 return scopedLockDetails; 925 } 926 927 928 929 /** 930 * Retrieves the backend lock timeout (in milliseconds) that should be used 931 * for the associated transaction, if specified. 932 * 933 * @return The backend lock timeout (in milliseconds) that should be used for 934 * the associated transaction, or {@code null} if none has been 935 * specified and the server should determine the backend lock 936 * timeout. 937 */ 938 @Nullable() 939 public Long getBackendLockTimeoutMillis() 940 { 941 return backendLockTimeoutMillis; 942 } 943 944 945 946 /** 947 * Retrieves the maximum number of times that the transaction may be retried 948 * if the initial attempt fails due to a lock conflict, if specified. 949 * 950 * @return The maximum number of times that the transaction may be retried if 951 * the initial attempt fails due to a lock conflict, or {@code null} 952 * if none has been specified and the server should determine the 953 * number of retry attempts. 954 */ 955 @Nullable() 956 public Integer getRetryAttempts() 957 { 958 return retryAttempts; 959 } 960 961 962 963 /** 964 * Retrieves the minimum transaction lock timeout (in milliseconds) that 965 * should be used for the associated transaction, if specified. This is the 966 * timeout value that will be used for the first attempt. Any subsequent 967 * attempts will have a lock timeout that is between the minimum and maximum 968 * timeout value. 969 * 970 * @return The minimum lock timeout (in milliseconds) that should 971 * be used for the associated transaction, or {@code null} if none 972 * has been specified and the server should determine the minimum 973 * transaction lock timeout. 974 */ 975 @Nullable() 976 public Long getMinTxnLockTimeoutMillis() 977 { 978 return minTxnLockTimeoutMillis; 979 } 980 981 982 983 /** 984 * Retrieves the maximum transaction lock timeout (in milliseconds) that 985 * should be used for the associated transaction, if specified. The timeout 986 * to be used for any retries will be between the minimum and maximum lock 987 * timeout values. 988 * 989 * @return The maximum lock timeout (in milliseconds) that should 990 * be used for the associated transaction, or {@code null} if none 991 * has been specified and the server should determine the maximum 992 * transaction lock timeout. 993 */ 994 @Nullable() 995 public Long getMaxTxnLockTimeoutMillis() 996 { 997 return maxTxnLockTimeoutMillis; 998 } 999 1000 1001 1002 /** 1003 * Indicates whether the settings in this control should be considered when 1004 * the operation is replicated to other servers in the topology. 1005 * 1006 * @return {@code true} if the control settings should be replicated, or 1007 * {@code false} if not. 1008 */ 1009 public boolean replicateControl() 1010 { 1011 return replicateControl; 1012 } 1013 1014 1015 1016 /** 1017 * Indicates whether to return a response control with transaction-related 1018 * information collected over the course of processing the associated 1019 * operation. 1020 * 1021 * @return {@code true} if the server should return a response control with 1022 * transaction-related information, or {@code false} if not. 1023 */ 1024 public boolean returnResponseControl() 1025 { 1026 return returnResponseControl; 1027 } 1028 1029 1030 1031 /** 1032 * {@inheritDoc} 1033 */ 1034 @Override() 1035 @NotNull() 1036 public String getControlName() 1037 { 1038 return INFO_CONTROL_NAME_TXN_SETTINGS_REQUEST.get(); 1039 } 1040 1041 1042 1043 /** 1044 * {@inheritDoc} 1045 */ 1046 @Override() 1047 public void toString(@NotNull final StringBuilder buffer) 1048 { 1049 buffer.append("TransactionSettingsRequestControl(isCritical="); 1050 buffer.append(isCritical()); 1051 1052 if (transactionName != null) 1053 { 1054 buffer.append(", transactionName='"); 1055 buffer.append(transactionName); 1056 buffer.append('\''); 1057 } 1058 1059 if (commitDurability != null) 1060 { 1061 buffer.append(", commitDurability='"); 1062 buffer.append(commitDurability.name()); 1063 buffer.append('\''); 1064 } 1065 1066 if (backendExclusiveLockBehavior != null) 1067 { 1068 buffer.append(", backendExclusiveLockBehavior='"); 1069 buffer.append(backendExclusiveLockBehavior.name()); 1070 buffer.append('\''); 1071 } 1072 1073 if (singleWriterLockBehavior != null) 1074 { 1075 buffer.append(", singleWriterLockBehavior='"); 1076 buffer.append(singleWriterLockBehavior.name()); 1077 buffer.append('\''); 1078 } 1079 1080 if (scopedLockDetails != null) 1081 { 1082 buffer.append(", scopedLockDetails="); 1083 scopedLockDetails.toString(buffer); 1084 } 1085 1086 if (backendLockTimeoutMillis != null) 1087 { 1088 buffer.append(", backendLockTimeoutMillis="); 1089 buffer.append(backendLockTimeoutMillis); 1090 } 1091 1092 if (retryAttempts != null) 1093 { 1094 buffer.append(", retryAttempts="); 1095 buffer.append(retryAttempts); 1096 } 1097 1098 if (minTxnLockTimeoutMillis != null) 1099 { 1100 buffer.append(", minTxnLockTimeoutMillis="); 1101 buffer.append(minTxnLockTimeoutMillis); 1102 } 1103 1104 if (maxTxnLockTimeoutMillis != null) 1105 { 1106 buffer.append(", maxTxnLockTimeoutMillis="); 1107 buffer.append(maxTxnLockTimeoutMillis); 1108 } 1109 1110 buffer.append(", replicateControl="); 1111 buffer.append(replicateControl); 1112 1113 buffer.append(", returnResponseControl="); 1114 buffer.append(returnResponseControl); 1115 1116 buffer.append(')'); 1117 } 1118}