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 }