001 /* 002 * Copyright 2013-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.controls; 022 023 024 025 import java.util.ArrayList; 026 027 import com.unboundid.asn1.ASN1Boolean; 028 import com.unboundid.asn1.ASN1Element; 029 import com.unboundid.asn1.ASN1Enumerated; 030 import com.unboundid.asn1.ASN1Long; 031 import com.unboundid.asn1.ASN1OctetString; 032 import com.unboundid.asn1.ASN1Sequence; 033 import com.unboundid.ldap.sdk.Control; 034 import com.unboundid.ldap.sdk.LDAPException; 035 import com.unboundid.ldap.sdk.ResultCode; 036 import com.unboundid.util.Debug; 037 import com.unboundid.util.NotMutable; 038 import com.unboundid.util.StaticUtils; 039 import com.unboundid.util.ThreadSafety; 040 import com.unboundid.util.ThreadSafetyLevel; 041 042 import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 043 044 045 046 /** 047 * <BLOCKQUOTE> 048 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID 049 * LDAP SDK for Java. It is not available for use in applications that 050 * include only the Standard Edition of the LDAP SDK, and is not supported for 051 * use in conjunction with non-UnboundID products. 052 * </BLOCKQUOTE> 053 * This class provides an implementation of an LDAP control that can be included 054 * in add, bind, modify, modify DN, and certain extended requests to indicate 055 * the level of replication assurance desired for the associated operation. 056 * <BR><BR> 057 * The OID for this control is 1.3.6.1.4.1.30221.2.5.28, and it may have a 058 * criticality of either TRUE or FALSE. It must have a value with the following 059 * encoding: 060 * <PRE> 061 * AssuredReplicationRequest ::= SEQUENCE { 062 * minimumLocalLevel [0] LocalLevel OPTIONAL, 063 * maximumLocalLevel [1] LocalLevel OPTIONAL, 064 * minimumRemoteLevel [2] RemoteLevel OPTIONAL, 065 * maximumRemoteLevel [3] RemoteLevel OPTIONAL, 066 * timeoutMillis [4] INTEGER (1 .. 2147483647) OPTIONAL, 067 * sendResponseImmediately [5] BOOLEAN DEFAULT FALSE, 068 * ... } 069 * 070 * LocalLevel ::= ENUMERATED { 071 * none (0), 072 * receivedAnyServer (1), 073 * processedAllServers (2), 074 * ... } 075 * 076 * RemoteLevel ::= ENUMERATED { 077 * none (0), 078 * receivedAnyRemoteLocation (1), 079 * receivedAllRemoteLocations (2), 080 * processedAllRemoteServers (3), 081 * ... } 082 * </PRE> 083 * <BR><BR> 084 * <H2>Example</H2> 085 * The following example demonstrates the use of the assured replication request 086 * control in conjunction with a delete operation to request that the server not 087 * return the delete result to the client until the delete has been applied to 088 * all available servers in the local data center and has also been replicated 089 * to at least one remote data center: 090 * <PRE> 091 * DeleteRequest deleteRequest = new DeleteRequest( 092 * "uid=test.user,ou=People,dc=example,dc=com"); 093 * deleteRequest.addControl(new AssuredReplicationRequestControl( 094 * AssuredReplicationLocalLevel.PROCESSED_ALL_SERVERS, 095 * AssuredReplicationRemoteLevel.RECEIVED_ANY_REMOTE_LOCATION, 096 * 5000L)); 097 * LDAPResult deleteResult = connection.delete(deleteRequest); 098 * 099 * if (deleteResult.getResultCode() == ResultCode.SUCCESS) 100 * { 101 * AssuredReplicationResponseControl assuredReplicationResponse = 102 * AssuredReplicationResponseControl.get(deleteResult); 103 * if (assuredReplicationResponse == null) 104 * { 105 * // The entry was deleted, but its replication could not be confirmed in 106 * // either the local or remote data centers. 107 * } 108 * else 109 * { 110 * if (assuredReplicationResponse.localAssuranceSatisfied()) 111 * { 112 * if (assuredReplicationResponse.remoteAssuranceSatisfied()) 113 * { 114 * // The entry was deleted. The delete has been applied across all 115 * // available local servers, and has been replicated to at least one 116 * // remote data center. 117 * } 118 * else 119 * { 120 * // The entry was deleted. The delete has been applied across all 121 * // available local servers, but cannot be confirmed to have yet 122 * // been replicated to any remote data centers. 123 * } 124 * } 125 * else if (assuredReplicationResponse.remoteAssuranceSatisfied()) 126 * { 127 * // The entry was deleted. The delete has been confirmed to have been 128 * // replicated to at least one remote data center, but cannot be 129 * // confirmed to have yet been applied to all available local servers. 130 * } 131 * else 132 * { 133 * // The entry was deleted, but its replication could not be confirmed 134 * // to either local servers or remote data centers. 135 * } 136 * } 137 * } 138 * else 139 * { 140 * // The entry could not be deleted. 141 * } 142 * </PRE> 143 * 144 * @see AssuredReplicationResponseControl 145 */ 146 @NotMutable() 147 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 148 public final class AssuredReplicationRequestControl 149 extends Control 150 { 151 /** 152 * The OID (1.3.6.1.4.1.30221.2.5.28) for the assured replication request 153 * control. 154 */ 155 public static final String ASSURED_REPLICATION_REQUEST_OID = 156 "1.3.6.1.4.1.30221.2.5.28"; 157 158 159 /** 160 * The BER type for the minimum local assurance level. 161 */ 162 private static final byte TYPE_MIN_LOCAL_LEVEL = (byte) 0x80; 163 164 165 /** 166 * The BER type for the maximum local assurance level. 167 */ 168 private static final byte TYPE_MAX_LOCAL_LEVEL = (byte) 0x81; 169 170 171 /** 172 * The BER type for the minimum remote assurance level. 173 */ 174 private static final byte TYPE_MIN_REMOTE_LEVEL = (byte) 0x82; 175 176 177 /** 178 * The BER type for the maximum remote assurance level. 179 */ 180 private static final byte TYPE_MAX_REMOTE_LEVEL = (byte) 0x83; 181 182 183 /** 184 * The BER type for the maximum remote assurance level. 185 */ 186 private static final byte TYPE_SEND_RESPONSE_IMMEDIATELY = (byte) 0x84; 187 188 189 /** 190 * The BER type for the timeout. 191 */ 192 private static final byte TYPE_TIMEOUT = (byte) 0x85; 193 194 195 196 /** 197 * The serial version UID for this serializable class. 198 */ 199 private static final long serialVersionUID = -2013933506118879241L; 200 201 202 203 // The requested maximum local assurance level. 204 private final AssuredReplicationLocalLevel maximumLocalLevel; 205 206 // The requested minimum local assurance level. 207 private final AssuredReplicationLocalLevel minimumLocalLevel; 208 209 // The requested maximum remote assurance level. 210 private final AssuredReplicationRemoteLevel maximumRemoteLevel; 211 212 // The requested minimum remote assurance level. 213 private final AssuredReplicationRemoteLevel minimumRemoteLevel; 214 215 // Indicates whether the server should immediately send the operation response 216 // without waiting for assurance processing. 217 private final boolean sendResponseImmediately; 218 219 // The maximum length of time in milliseconds that the server should wait for 220 // the desired assurance level to be attained. 221 private final Long timeoutMillis; 222 223 224 225 /** 226 * Creates a new assured replication request control with the provided 227 * information. It will not be critical. 228 * 229 * @param minimumLocalLevel The minimum replication assurance level desired 230 * for servers in the same location as the server 231 * receiving the change. This may be overridden 232 * by the server if the associated operation 233 * matches an assured replication criteria with a 234 * higher local assurance level. If this is 235 * {@code null}, then the server will determine 236 * minimum local assurance level for the 237 * operation. 238 * @param minimumRemoteLevel The minimum replication assurance level desired 239 * for servers in different locations from the 240 * server receiving the change. This may be 241 * overridden by the server if the associated 242 * operation matches an assured replication 243 * criteria with a higher remote assurance level. 244 * If this is {@code null}, then the server will 245 * determine the remote assurance level for the 246 * operation. 247 * @param timeoutMillis The maximum length of time in milliseconds to 248 * wait for the desired assurance to be satisfied. 249 * If this is {@code null}, then the server will 250 * determine the timeout to use. 251 */ 252 public AssuredReplicationRequestControl( 253 final AssuredReplicationLocalLevel minimumLocalLevel, 254 final AssuredReplicationRemoteLevel minimumRemoteLevel, 255 final Long timeoutMillis) 256 { 257 this(false, minimumLocalLevel, null, minimumRemoteLevel, null, 258 timeoutMillis, false); 259 } 260 261 262 263 /** 264 * Creates a new assured replication request control with the provided 265 * information. 266 * 267 * @param isCritical Indicates whether the control should be 268 * marked critical. 269 * @param minimumLocalLevel The minimum replication assurance level 270 * desired for servers in the same location 271 * as the server receiving the change. This 272 * may be overridden by the server if the 273 * associated operation matches an assured 274 * replication criteria with a higher local 275 * assurance level. If this is {@code null}, 276 * then the server will determine the minimum 277 * local assurance level for the operation. 278 * @param maximumLocalLevel The maximum replication assurance level 279 * desired for servers in the same location 280 * as the server receiving the change. This 281 * may override the server configuration if 282 * the operation matches an assured 283 * replication criteria that would have 284 * otherwise used a higher local assurance 285 * level. If this is {@code null}, then the 286 * server will determine the maximum local 287 * assurance level for the operation. 288 * @param minimumRemoteLevel The minimum replication assurance level 289 * desired for servers in different locations 290 * from the server receiving the change. 291 * This may be overridden by the server if 292 * the associated operation matches an 293 * assured replication criteria with a higher 294 * remote assurance level. If this is 295 * {@code null}, then the server will 296 * determine the minimum remote assurance 297 * level for the operation. 298 * @param maximumRemoteLevel The maximum replication assurance level 299 * desired for servers in different locations 300 * from the server receiving the change. 301 * This may override the server configuration 302 * if the operation matches an assured 303 * replication criteria that would have 304 * otherwise used a higher remote assurance 305 * level. If this is {@code null}, then the 306 * server will determine the maximum remote 307 * assurance level for the operation. 308 * @param timeoutMillis The maximum length of time in milliseconds 309 * to wait for the desired assurance to be 310 * satisfied. If this is {@code null}, then 311 * the server will determine the timeout to 312 * use. 313 * @param sendResponseImmediately Indicates whether the server should 314 * send the response to the client immediately after the change 315 * has been applied to the server receiving the change, without 316 * waiting for the desired assurance to be satisfied. 317 */ 318 public AssuredReplicationRequestControl(final boolean isCritical, 319 final AssuredReplicationLocalLevel minimumLocalLevel, 320 final AssuredReplicationLocalLevel maximumLocalLevel, 321 final AssuredReplicationRemoteLevel minimumRemoteLevel, 322 final AssuredReplicationRemoteLevel maximumRemoteLevel, 323 final Long timeoutMillis, final boolean sendResponseImmediately) 324 { 325 super(ASSURED_REPLICATION_REQUEST_OID, isCritical, 326 encodeValue(minimumLocalLevel, maximumLocalLevel, minimumRemoteLevel, 327 maximumRemoteLevel, sendResponseImmediately, timeoutMillis)); 328 329 this.minimumLocalLevel = minimumLocalLevel; 330 this.maximumLocalLevel = maximumLocalLevel; 331 this.minimumRemoteLevel = minimumRemoteLevel; 332 this.maximumRemoteLevel = maximumRemoteLevel; 333 this.sendResponseImmediately = sendResponseImmediately; 334 this.timeoutMillis = timeoutMillis; 335 } 336 337 338 339 /** 340 * Creates a new assured replication request control from the provided generic 341 * control. 342 * 343 * @param c The generic control to decode as an assured replication request 344 * control. It must not be {@code null}. 345 * 346 * @throws LDAPException If the provided generic control cannot be parsed as 347 * an assured replication request control. 348 */ 349 public AssuredReplicationRequestControl(final Control c) 350 throws LDAPException 351 { 352 super(c); 353 354 final ASN1OctetString value = c.getValue(); 355 if (value == null) 356 { 357 throw new LDAPException(ResultCode.DECODING_ERROR, 358 ERR_ASSURED_REPLICATION_REQUEST_NO_VALUE.get()); 359 } 360 361 AssuredReplicationLocalLevel maxLocalLevel = null; 362 AssuredReplicationLocalLevel minLocalLevel = null; 363 AssuredReplicationRemoteLevel maxRemoteLevel = null; 364 AssuredReplicationRemoteLevel minRemoteLevel = null; 365 boolean sendImmediately = false; 366 Long timeout = null; 367 368 try 369 { 370 for (final ASN1Element e : 371 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 372 { 373 switch (e.getType()) 374 { 375 case TYPE_MIN_LOCAL_LEVEL: 376 int intValue = ASN1Enumerated.decodeAsEnumerated(e).intValue(); 377 minLocalLevel = AssuredReplicationLocalLevel.valueOf(intValue); 378 if (minLocalLevel == null) 379 { 380 throw new LDAPException(ResultCode.DECODING_ERROR, 381 ERR_ASSURED_REPLICATION_REQUEST_INVALID_MIN_LOCAL_LEVEL.get( 382 intValue)); 383 } 384 break; 385 386 case TYPE_MAX_LOCAL_LEVEL: 387 intValue = ASN1Enumerated.decodeAsEnumerated(e).intValue(); 388 maxLocalLevel = AssuredReplicationLocalLevel.valueOf(intValue); 389 if (maxLocalLevel == null) 390 { 391 throw new LDAPException(ResultCode.DECODING_ERROR, 392 ERR_ASSURED_REPLICATION_REQUEST_INVALID_MAX_LOCAL_LEVEL.get( 393 intValue)); 394 } 395 break; 396 397 case TYPE_MIN_REMOTE_LEVEL: 398 intValue = ASN1Enumerated.decodeAsEnumerated(e).intValue(); 399 minRemoteLevel = AssuredReplicationRemoteLevel.valueOf(intValue); 400 if (minRemoteLevel == null) 401 { 402 throw new LDAPException(ResultCode.DECODING_ERROR, 403 ERR_ASSURED_REPLICATION_REQUEST_INVALID_MIN_REMOTE_LEVEL.get( 404 intValue)); 405 } 406 break; 407 408 case TYPE_MAX_REMOTE_LEVEL: 409 intValue = ASN1Enumerated.decodeAsEnumerated(e).intValue(); 410 maxRemoteLevel = AssuredReplicationRemoteLevel.valueOf(intValue); 411 if (maxRemoteLevel == null) 412 { 413 throw new LDAPException(ResultCode.DECODING_ERROR, 414 ERR_ASSURED_REPLICATION_REQUEST_INVALID_MAX_REMOTE_LEVEL.get( 415 intValue)); 416 } 417 break; 418 419 case TYPE_SEND_RESPONSE_IMMEDIATELY: 420 sendImmediately = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 421 break; 422 423 case TYPE_TIMEOUT: 424 timeout = ASN1Long.decodeAsLong(e).longValue(); 425 break; 426 427 default: 428 throw new LDAPException(ResultCode.DECODING_ERROR, 429 ERR_ASSURED_REPLICATION_REQUEST_UNEXPECTED_ELEMENT_TYPE.get( 430 StaticUtils.toHex(e.getType()))); 431 } 432 } 433 } 434 catch (final LDAPException le) 435 { 436 Debug.debugException(le); 437 throw le; 438 } 439 catch (final Exception e) 440 { 441 Debug.debugException(e); 442 throw new LDAPException(ResultCode.DECODING_ERROR, 443 ERR_ASSURED_REPLICATION_REQUEST_ERROR_DECODING_VALUE.get( 444 StaticUtils.getExceptionMessage(e)), 445 e); 446 } 447 448 minimumLocalLevel = minLocalLevel; 449 maximumLocalLevel = maxLocalLevel; 450 minimumRemoteLevel = minRemoteLevel; 451 maximumRemoteLevel = maxRemoteLevel; 452 sendResponseImmediately = sendImmediately; 453 timeoutMillis = timeout; 454 } 455 456 457 458 /** 459 * Encodes the provided information as needed for use as the value of this 460 * control. 461 * 462 * @param minimumLocalLevel The minimum replication assurance level 463 * desired for servers in the same location 464 * as the server receiving the change. This 465 * may be overridden by the server if the 466 * associated operation matches an assured 467 * replication criteria with a higher local 468 * assurance level. If this is {@code null}, 469 * then the server will determine the minimum 470 * local assurance level for the operation. 471 * @param maximumLocalLevel The maximum replication assurance level 472 * desired for servers in the same location 473 * as the server receiving the change. This 474 * may override the server configuration if 475 * the operation matches an assured 476 * replication criteria that would have 477 * otherwise used a higher local assurance 478 * level. If this is {@code null}, then the 479 * server will determine the maximum local 480 * assurance level for the operation. 481 * @param minimumRemoteLevel The minimum replication assurance level 482 * desired for servers in different locations 483 * from the server receiving the change. 484 * This may be overridden by the server if 485 * the associated operation matches an 486 * assured replication criteria with a higher 487 * remote assurance level. If this is 488 * {@code null}, then the server will 489 * determine the minimum remote assurance 490 * level for the operation. 491 * @param maximumRemoteLevel The maximum replication assurance level 492 * desired for servers in different locations 493 * from the server receiving the change. 494 * This may override the server configuration 495 * if the operation matches an assured 496 * replication criteria that would have 497 * otherwise used a higher remote assurance 498 * level. If this is {@code null}, then the 499 * server will determine the maximum remote 500 * assurance level for the operation. 501 * @param timeoutMillis The maximum length of time in milliseconds 502 * to wait for the desired assurance to be 503 * satisfied. If this is {@code null}, then 504 * the server will determine the timeout to 505 * use. 506 * @param sendResponseImmediately Indicates whether the server should 507 * send the response to the client immediately after the change 508 * has been applied to the server receiving the change, without 509 * waiting for the desired assurance to be satisfied. 510 * 511 * @return The ASN.1 octet string containing the encoded value. 512 */ 513 private static ASN1OctetString encodeValue( 514 final AssuredReplicationLocalLevel minimumLocalLevel, 515 final AssuredReplicationLocalLevel maximumLocalLevel, 516 final AssuredReplicationRemoteLevel minimumRemoteLevel, 517 final AssuredReplicationRemoteLevel maximumRemoteLevel, 518 final boolean sendResponseImmediately, 519 final Long timeoutMillis) 520 { 521 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(6); 522 523 if (minimumLocalLevel != null) 524 { 525 elements.add(new ASN1Enumerated(TYPE_MIN_LOCAL_LEVEL, 526 minimumLocalLevel.intValue())); 527 } 528 529 if (maximumLocalLevel != null) 530 { 531 elements.add(new ASN1Enumerated(TYPE_MAX_LOCAL_LEVEL, 532 maximumLocalLevel.intValue())); 533 } 534 535 if (minimumRemoteLevel != null) 536 { 537 elements.add(new ASN1Enumerated(TYPE_MIN_REMOTE_LEVEL, 538 minimumRemoteLevel.intValue())); 539 } 540 541 if (maximumRemoteLevel != null) 542 { 543 elements.add(new ASN1Enumerated(TYPE_MAX_REMOTE_LEVEL, 544 maximumRemoteLevel.intValue())); 545 } 546 547 if (sendResponseImmediately) 548 { 549 elements.add(new ASN1Boolean(TYPE_SEND_RESPONSE_IMMEDIATELY, true)); 550 } 551 552 if (timeoutMillis != null) 553 { 554 elements.add(new ASN1Long(TYPE_TIMEOUT, timeoutMillis)); 555 } 556 557 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 558 } 559 560 561 562 /** 563 * Retrieves the minimum desired replication level of assurance for local 564 * servers (i.e., servers in the same location as the server that originally 565 * received the change), if defined. This may be overridden by the server if 566 * the associated operation matches an assured replication criteria with a 567 * higher local assurance level. 568 * 569 * @return The minimum desired replication level of assurance for local 570 * servers, or {@code null} if the server should determine the 571 * minimum local assurance level for the operation. 572 */ 573 public AssuredReplicationLocalLevel getMinimumLocalLevel() 574 { 575 return minimumLocalLevel; 576 } 577 578 579 580 /** 581 * Retrieves the maximum desired replication level of assurance for local 582 * servers (i.e., servers in the same location as the server that originally 583 * received the change), if defined. This may override the server 584 * configuration if the operation matches an assured replication criteria that 585 * would have otherwise used a higher local assurance level. 586 * 587 * @return The maximum desired replication level of assurance for local 588 * servers, or {@code null} if the server should determine the 589 * maximum local assurance level for the operation. 590 */ 591 public AssuredReplicationLocalLevel getMaximumLocalLevel() 592 { 593 return maximumLocalLevel; 594 } 595 596 597 598 /** 599 * Retrieves the minimum desired replication level of assurance for remote 600 * servers (i.e., servers in locations different from the server that 601 * originally received the change), if defined. This may be overridden by the 602 * server if the associated operation matches an assured replication 603 * criteria with a higher remote assurance level. 604 * 605 * @return The minimum desired replication level of assurance for remote 606 * servers, or {@code null} if the server should determine the 607 * minimum remote assurance level for the operation. 608 */ 609 public AssuredReplicationRemoteLevel getMinimumRemoteLevel() 610 { 611 return minimumRemoteLevel; 612 } 613 614 615 616 /** 617 * Retrieves the maximum desired replication level of assurance for remote 618 * servers (i.e., servers in locations different from the server that 619 * originally received the change), if defined. This may override the server 620 * configuration if the operation matches an assured replication criteria that 621 * would have otherwise used a higher remote assurance level. 622 * 623 * @return The maximum desired replication level of assurance for remote 624 * servers, or {@code null} if the server should determine the 625 * maximum remote assurance level for the operation. 626 */ 627 public AssuredReplicationRemoteLevel getMaximumRemoteLevel() 628 { 629 return maximumRemoteLevel; 630 } 631 632 633 634 /** 635 * Indicates whether the server that originally received the change should 636 * return the operation result immediately, without waiting for the requested 637 * assurance processing to complete. 638 * 639 * @return {@code false} if the server should wait to return the operation 640 * result until the desired assurance has been attained or a timeout 641 * has occurred, or {@code true} if the server should return the 642 * result immediately. 643 */ 644 public boolean sendResponseImmediately() 645 { 646 return sendResponseImmediately; 647 } 648 649 650 651 /** 652 * Retrieves the maximum length of time in milliseconds that the operation 653 * response should be delayed while waiting for the desired level of 654 * assurance to be attained. 655 * 656 * @return The maximum length of time in milliseconds that the operation 657 * response should be delayed while waiting for the desired level of 658 * assurance to be attained. 659 */ 660 public Long getTimeoutMillis() 661 { 662 return timeoutMillis; 663 } 664 665 666 667 /** 668 * {@inheritDoc} 669 */ 670 @Override() 671 public String getControlName() 672 { 673 return INFO_CONTROL_NAME_ASSURED_REPLICATION_REQUEST.get(); 674 } 675 676 677 678 /** 679 * {@inheritDoc} 680 */ 681 @Override() 682 public void toString(final StringBuilder buffer) 683 { 684 buffer.append("AssuredReplicationRequestControl(isCritical="); 685 buffer.append(isCritical()); 686 687 if (minimumLocalLevel != null) 688 { 689 buffer.append(", minimumLocalLevel="); 690 buffer.append(minimumLocalLevel.name()); 691 } 692 693 if (maximumLocalLevel != null) 694 { 695 buffer.append(", maximumLocalLevel="); 696 buffer.append(maximumLocalLevel.name()); 697 } 698 699 if (minimumRemoteLevel != null) 700 { 701 buffer.append(", minimumRemoteLevel="); 702 buffer.append(minimumRemoteLevel.name()); 703 } 704 705 if (maximumRemoteLevel != null) 706 { 707 buffer.append(", maximumRemoteLevel="); 708 buffer.append(maximumRemoteLevel.name()); 709 } 710 711 buffer.append(", sendResponseImmediately="); 712 buffer.append(sendResponseImmediately); 713 714 if (timeoutMillis != null) 715 { 716 buffer.append(", timeoutMillis="); 717 buffer.append(timeoutMillis); 718 } 719 720 buffer.append(')'); 721 } 722 }