001/* 002 * Copyright 2011-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2011-2017 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 */ 021package com.unboundid.ldap.listener; 022 023 024 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collection; 028import java.util.EnumSet; 029import java.util.HashSet; 030import java.util.Iterator; 031import java.util.LinkedHashMap; 032import java.util.List; 033import java.util.Map; 034import java.util.Set; 035import java.util.logging.Handler; 036 037import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor; 038import com.unboundid.ldap.sdk.DN; 039import com.unboundid.ldap.sdk.Entry; 040import com.unboundid.ldap.sdk.LDAPException; 041import com.unboundid.ldap.sdk.OperationType; 042import com.unboundid.ldap.sdk.ReadOnlyEntry; 043import com.unboundid.ldap.sdk.ResultCode; 044import com.unboundid.ldap.sdk.Version; 045import com.unboundid.ldap.sdk.schema.Schema; 046import com.unboundid.util.Mutable; 047import com.unboundid.util.NotExtensible; 048import com.unboundid.util.StaticUtils; 049import com.unboundid.util.ThreadSafety; 050import com.unboundid.util.ThreadSafetyLevel; 051 052import static com.unboundid.ldap.listener.ListenerMessages.*; 053 054 055 056/** 057 * This class provides a simple data structure with information that may be 058 * used to control the behavior of an {@link InMemoryDirectoryServer} instance. 059 * At least one base DN must be specified. For all other properties, the 060 * following default values will be used unless an alternate configuration is 061 * provided: 062 * <UL> 063 * <LI>Listeners: The server will provide a single listener that will use an 064 * automatically-selected port on all interfaces, which will not use SSL 065 * or StartTLS.</LI> 066 * <LI>Allowed Operation Types: All types of operations will be allowed.</LI> 067 * <LI>Authentication Required Operation Types: Authentication will not be 068 * required for any types of operations.</LI> 069 * <LI>Schema: The server will use a schema with a number of standard 070 * attribute types and object classes.</LI> 071 * <LI>Additional Bind Credentials: The server will not have any additional 072 * bind credentials.</LI> 073 * <LI>Referential Integrity Attributes: Referential integrity will not be 074 * maintained.</LI> 075 * <LI>Generate Operational Attributes: The server will automatically 076 * generate a number of operational attributes.</LI> 077 * <LI>Extended Operation Handlers: The server will support the password 078 * modify extended operation as defined in RFC 3062, the start and end 079 * transaction extended operations as defined in RFC 5805, and the 080 * "Who Am I?" extended operation as defined in RFC 4532.</LI> 081 * <LI>SASL Bind Handlers: The server will support the SASL PLAIN mechanism 082 * as defined in RFC 4616.</LI> 083 * <LI>Max ChangeLog Entries: The server will not provide an LDAP 084 * changelog.</LI> 085 * <LI>Access Log Handler: The server will not perform any access 086 * logging.</LI> 087 * <LI>Code Log Handler: The server will not perform any code logging.</LI> 088 * <LI>LDAP Debug Log Handler: The server will not perform any LDAP debug 089 * logging.</LI> 090 * <LI>Listener Exception Handler: The server will not use a listener 091 * exception handler.</LI> 092 * <LI>Maximum Size Limit: The server will not enforce a maximum search size 093 * limit.</LI> 094 * </UL> 095 */ 096@NotExtensible() 097@Mutable() 098@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 099public class InMemoryDirectoryServerConfig 100{ 101 // Indicates whether to enforce the requirement that attribute values comply 102 // with the associated attribute syntax. 103 private boolean enforceAttributeSyntaxCompliance; 104 105 // Indicates whether to enforce the requirement that entries contain exactly 106 // one structural object class. 107 private boolean enforceSingleStructuralObjectClass; 108 109 // Indicates whether to automatically generate operational attributes. 110 private boolean generateOperationalAttributes; 111 112 // Indicates whether the code log should include sample code for processing 113 // the requests. 114 private boolean includeRequestProcessingInCodeLog; 115 116 // The base DNs to use for the LDAP listener. 117 private DN[] baseDNs; 118 119 // The log handler that should be used to record access log messages about 120 // operations processed by the server. 121 private Handler accessLogHandler; 122 123 // The log handler that should be used to record detailed protocol-level 124 // messages about LDAP operations processed by the server. 125 private Handler ldapDebugLogHandler; 126 127 // The maximum number of entries to retain in a generated changelog. 128 private int maxChangeLogEntries; 129 130 // The maximum number of concurrent connections that will be allowed. 131 private int maxConnections; 132 133 // The maximum number of entries that may be returned in any single search 134 // operation. 135 private int maxSizeLimit; 136 137 // The exception handler that should be used for the listener. 138 private LDAPListenerExceptionHandler exceptionHandler; 139 140 // The extended operation handlers that may be used to process extended 141 // operations in the server. 142 private final List<InMemoryExtendedOperationHandler> 143 extendedOperationHandlers; 144 145 // The listener configurations that should be used for accepting connections 146 // to the server. 147 private final List<InMemoryListenerConfig> listenerConfigs; 148 149 // The operation interceptors that should be used with the in-memory directory 150 // server. 151 private final List<InMemoryOperationInterceptor> operationInterceptors; 152 153 // The SASL bind handlers that may be used to process SASL bind requests in 154 // the server. 155 private final List<InMemorySASLBindHandler> saslBindHandlers; 156 157 // The names or OIDs of the attributes for which to maintain equality indexes. 158 private final List<String> equalityIndexAttributes; 159 160 // A set of additional credentials that can be used for binding without 161 // requiring a corresponding entry in the data set. 162 private final Map<DN,byte[]> additionalBindCredentials; 163 164 // The entry to use for the server root DSE. 165 private ReadOnlyEntry rootDSEEntry; 166 167 // The schema to use for the server. 168 private Schema schema; 169 170 // The set of operation types that will be supported by the server. 171 private final Set<OperationType> allowedOperationTypes; 172 173 // The set of operation types for which authentication will be required. 174 private final Set<OperationType> authenticationRequiredOperationTypes; 175 176 // The set of attributes for which referential integrity should be maintained. 177 private final Set<String> referentialIntegrityAttributes; 178 179 // The path to a file that should be written with code that may be used to 180 // issue the requests received by the server. 181 private String codeLogPath; 182 183 // The vendor name to report in the server root DSE. 184 private String vendorName; 185 186 // The vendor version to report in the server root DSE. 187 private String vendorVersion; 188 189 190 191 /** 192 * Creates a new in-memory directory server config object with the provided 193 * set of base DNs. 194 * 195 * @param baseDNs The set of base DNs to use for the server. It must not 196 * be {@code null} or empty. 197 * 198 * @throws LDAPException If the provided set of base DN strings is null or 199 * empty, or if any of the provided base DN strings 200 * cannot be parsed as a valid DN. 201 */ 202 public InMemoryDirectoryServerConfig(final String... baseDNs) 203 throws LDAPException 204 { 205 this(parseDNs(Schema.getDefaultStandardSchema(), baseDNs)); 206 } 207 208 209 210 /** 211 * Creates a new in-memory directory server config object with the default 212 * settings. 213 * 214 * @param baseDNs The set of base DNs to use for the server. It must not 215 * be {@code null} or empty. 216 * 217 * @throws LDAPException If the provided set of base DNs is null or empty. 218 */ 219 public InMemoryDirectoryServerConfig(final DN... baseDNs) 220 throws LDAPException 221 { 222 if ((baseDNs == null) || (baseDNs.length == 0)) 223 { 224 throw new LDAPException(ResultCode.PARAM_ERROR, 225 ERR_MEM_DS_CFG_NO_BASE_DNS.get()); 226 } 227 228 this.baseDNs = baseDNs; 229 230 listenerConfigs = new ArrayList<InMemoryListenerConfig>(1); 231 listenerConfigs.add(InMemoryListenerConfig.createLDAPConfig("default")); 232 233 additionalBindCredentials = new LinkedHashMap<DN,byte[]>(1); 234 accessLogHandler = null; 235 ldapDebugLogHandler = null; 236 enforceAttributeSyntaxCompliance = true; 237 enforceSingleStructuralObjectClass = true; 238 generateOperationalAttributes = true; 239 maxChangeLogEntries = 0; 240 maxConnections = 0; 241 maxSizeLimit = 0; 242 exceptionHandler = null; 243 equalityIndexAttributes = new ArrayList<String>(10); 244 rootDSEEntry = null; 245 schema = Schema.getDefaultStandardSchema(); 246 allowedOperationTypes = EnumSet.allOf(OperationType.class); 247 authenticationRequiredOperationTypes = EnumSet.noneOf(OperationType.class); 248 referentialIntegrityAttributes = new HashSet<String>(0); 249 vendorName = "UnboundID Corp."; 250 vendorVersion = Version.FULL_VERSION_STRING; 251 codeLogPath = null; 252 includeRequestProcessingInCodeLog = false; 253 254 operationInterceptors = new ArrayList<InMemoryOperationInterceptor>(5); 255 256 extendedOperationHandlers = 257 new ArrayList<InMemoryExtendedOperationHandler>(3); 258 extendedOperationHandlers.add(new PasswordModifyExtendedOperationHandler()); 259 extendedOperationHandlers.add(new TransactionExtendedOperationHandler()); 260 extendedOperationHandlers.add(new WhoAmIExtendedOperationHandler()); 261 262 saslBindHandlers = new ArrayList<InMemorySASLBindHandler>(1); 263 saslBindHandlers.add(new PLAINBindHandler()); 264 } 265 266 267 268 /** 269 * Creates a new in-memory directory server config object that is a duplicate 270 * of the provided config and may be altered without impacting the state of 271 * the given config object. 272 * 273 * @param cfg The in-memory directory server config object for to be 274 * duplicated. 275 */ 276 public InMemoryDirectoryServerConfig(final InMemoryDirectoryServerConfig cfg) 277 { 278 baseDNs = new DN[cfg.baseDNs.length]; 279 System.arraycopy(cfg.baseDNs, 0, baseDNs, 0, baseDNs.length); 280 281 listenerConfigs = new ArrayList<InMemoryListenerConfig>( 282 cfg.listenerConfigs); 283 284 operationInterceptors = new ArrayList<InMemoryOperationInterceptor>( 285 cfg.operationInterceptors); 286 287 extendedOperationHandlers = new ArrayList<InMemoryExtendedOperationHandler>( 288 cfg.extendedOperationHandlers); 289 290 saslBindHandlers = 291 new ArrayList<InMemorySASLBindHandler>(cfg.saslBindHandlers); 292 293 additionalBindCredentials = 294 new LinkedHashMap<DN,byte[]>(cfg.additionalBindCredentials); 295 296 referentialIntegrityAttributes = 297 new HashSet<String>(cfg.referentialIntegrityAttributes); 298 299 allowedOperationTypes = EnumSet.noneOf(OperationType.class); 300 allowedOperationTypes.addAll(cfg.allowedOperationTypes); 301 302 authenticationRequiredOperationTypes = EnumSet.noneOf(OperationType.class); 303 authenticationRequiredOperationTypes.addAll( 304 cfg.authenticationRequiredOperationTypes); 305 306 equalityIndexAttributes = 307 new ArrayList<String>(cfg.equalityIndexAttributes); 308 309 enforceAttributeSyntaxCompliance = cfg.enforceAttributeSyntaxCompliance; 310 enforceSingleStructuralObjectClass = cfg.enforceSingleStructuralObjectClass; 311 generateOperationalAttributes = cfg.generateOperationalAttributes; 312 accessLogHandler = cfg.accessLogHandler; 313 ldapDebugLogHandler = cfg.ldapDebugLogHandler; 314 maxChangeLogEntries = cfg.maxChangeLogEntries; 315 maxConnections = cfg.maxConnections; 316 maxSizeLimit = cfg.maxSizeLimit; 317 exceptionHandler = cfg.exceptionHandler; 318 rootDSEEntry = cfg.rootDSEEntry; 319 schema = cfg.schema; 320 vendorName = cfg.vendorName; 321 vendorVersion = cfg.vendorVersion; 322 codeLogPath = cfg.codeLogPath; 323 includeRequestProcessingInCodeLog = cfg.includeRequestProcessingInCodeLog; 324 } 325 326 327 328 /** 329 * Retrieves the set of base DNs that should be used for the directory server. 330 * 331 * @return The set of base DNs that should be used for the directory server. 332 */ 333 public DN[] getBaseDNs() 334 { 335 return baseDNs; 336 } 337 338 339 340 /** 341 * Specifies the set of base DNs that should be used for the directory server. 342 * 343 * @param baseDNs The set of base DNs that should be used for the directory 344 * server. It must not be {@code null} or empty. 345 * 346 * @throws LDAPException If the provided set of base DN strings is null or 347 * empty, or if any of the provided base DN strings 348 * cannot be parsed as a valid DN. 349 */ 350 public void setBaseDNs(final String... baseDNs) 351 throws LDAPException 352 { 353 setBaseDNs(parseDNs(schema, baseDNs)); 354 } 355 356 357 358 /** 359 * Specifies the set of base DNs that should be used for the directory server. 360 * 361 * @param baseDNs The set of base DNs that should be used for the directory 362 * server. It must not be {@code null} or empty. 363 * 364 * @throws LDAPException If the provided set of base DNs is null or empty. 365 */ 366 public void setBaseDNs(final DN... baseDNs) 367 throws LDAPException 368 { 369 if ((baseDNs == null) || (baseDNs.length == 0)) 370 { 371 throw new LDAPException(ResultCode.PARAM_ERROR, 372 ERR_MEM_DS_CFG_NO_BASE_DNS.get()); 373 } 374 375 this.baseDNs = baseDNs; 376 } 377 378 379 380 /** 381 * Retrieves the list of listener configurations that should be used for the 382 * directory server. 383 * 384 * @return The list of listener configurations that should be used for the 385 * directory server. 386 */ 387 public List<InMemoryListenerConfig> getListenerConfigs() 388 { 389 return listenerConfigs; 390 } 391 392 393 394 /** 395 * Specifies the configurations for all listeners that should be used for the 396 * directory server. 397 * 398 * @param listenerConfigs The configurations for all listeners that should 399 * be used for the directory server. It must not be 400 * {@code null} or empty, and it must not contain 401 * multiple configurations with the same name. 402 * 403 * @throws LDAPException If there is a problem with the provided set of 404 * listener configurations. 405 */ 406 public void setListenerConfigs( 407 final InMemoryListenerConfig... listenerConfigs) 408 throws LDAPException 409 { 410 setListenerConfigs(StaticUtils.toList(listenerConfigs)); 411 } 412 413 414 415 /** 416 * Specifies the configurations for all listeners that should be used for the 417 * directory server. 418 * 419 * @param listenerConfigs The configurations for all listeners that should 420 * be used for the directory server. It must not be 421 * {@code null} or empty, and it must not contain 422 * multiple configurations with the same name. 423 * 424 * @throws LDAPException If there is a problem with the provided set of 425 * listener configurations. 426 */ 427 public void setListenerConfigs( 428 final Collection<InMemoryListenerConfig> listenerConfigs) 429 throws LDAPException 430 { 431 if ((listenerConfigs == null) || listenerConfigs.isEmpty()) 432 { 433 throw new LDAPException(ResultCode.PARAM_ERROR, 434 ERR_MEM_DS_CFG_NO_LISTENERS.get()); 435 } 436 437 final HashSet<String> listenerNames = 438 new HashSet<String>(listenerConfigs.size()); 439 for (final InMemoryListenerConfig c : listenerConfigs) 440 { 441 final String name = StaticUtils.toLowerCase(c.getListenerName()); 442 if (listenerNames.contains(name)) 443 { 444 throw new LDAPException(ResultCode.PARAM_ERROR, 445 ERR_MEM_DS_CFG_CONFLICTING_LISTENER_NAMES.get(name)); 446 } 447 else 448 { 449 listenerNames.add(name); 450 } 451 } 452 453 this.listenerConfigs.clear(); 454 this.listenerConfigs.addAll(listenerConfigs); 455 } 456 457 458 459 /** 460 * Retrieves the set of operation types that will be allowed by the server. 461 * Note that if the server is configured to support StartTLS, then it will be 462 * allowed even if other types of extended operations are not allowed. 463 * 464 * @return The set of operation types that will be allowed by the server. 465 */ 466 public Set<OperationType> getAllowedOperationTypes() 467 { 468 return allowedOperationTypes; 469 } 470 471 472 473 /** 474 * Specifies the set of operation types that will be allowed by the server. 475 * Note that if the server is configured to support StartTLS, then it will be 476 * allowed even if other types of extended operations are not allowed. 477 * 478 * @param operationTypes The set of operation types that will be allowed by 479 * the server. 480 */ 481 public void setAllowedOperationTypes(final OperationType... operationTypes) 482 { 483 allowedOperationTypes.clear(); 484 if (operationTypes != null) 485 { 486 allowedOperationTypes.addAll(Arrays.asList(operationTypes)); 487 } 488 } 489 490 491 492 /** 493 * Specifies the set of operation types that will be allowed by the server. 494 * Note that if the server is configured to support StartTLS, then it will be 495 * allowed even if other types of extended operations are not allowed. 496 * 497 * @param operationTypes The set of operation types that will be allowed by 498 * the server. 499 */ 500 public void setAllowedOperationTypes( 501 final Collection<OperationType> operationTypes) 502 { 503 allowedOperationTypes.clear(); 504 if (operationTypes != null) 505 { 506 allowedOperationTypes.addAll(operationTypes); 507 } 508 } 509 510 511 512 /** 513 * Retrieves the set of operation types that will only be allowed for 514 * authenticated clients. Note that authentication will never be required for 515 * bind operations, and if the server is configured to support StartTLS, then 516 * authentication will never be required for StartTLS operations even if it 517 * is required for other types of extended operations. 518 * 519 * @return The set of operation types that will only be allowed for 520 * authenticated clients. 521 */ 522 public Set<OperationType> getAuthenticationRequiredOperationTypes() 523 { 524 return authenticationRequiredOperationTypes; 525 } 526 527 528 529 /** 530 * Specifies the set of operation types that will only be allowed for 531 * authenticated clients. Note that authentication will never be required for 532 * bind operations, and if the server is configured to support StartTLS, then 533 * authentication will never be required for StartTLS operations even if it 534 * is required for other types of extended operations. 535 * 536 * @param operationTypes The set of operation types that will be allowed for 537 * authenticated clients. 538 */ 539 public void setAuthenticationRequiredOperationTypes( 540 final OperationType... operationTypes) 541 { 542 authenticationRequiredOperationTypes.clear(); 543 if (operationTypes != null) 544 { 545 authenticationRequiredOperationTypes.addAll( 546 Arrays.asList(operationTypes)); 547 } 548 } 549 550 551 552 /** 553 * Specifies the set of operation types that will only be allowed for 554 * authenticated clients. Note that authentication will never be required for 555 * bind operations, and if the server is configured to support StartTLS, then 556 * authentication will never be required for StartTLS operations even if it 557 * is required for other types of extended operations. 558 * 559 * @param operationTypes The set of operation types that will be allowed for 560 * authenticated clients. 561 */ 562 public void setAuthenticationRequiredOperationTypes( 563 final Collection<OperationType> operationTypes) 564 { 565 authenticationRequiredOperationTypes.clear(); 566 if (operationTypes != null) 567 { 568 authenticationRequiredOperationTypes.addAll(operationTypes); 569 } 570 } 571 572 573 574 /** 575 * Retrieves a map containing DNs and passwords of additional users that will 576 * be allowed to bind to the server, even if their entries do not exist in the 577 * data set. This can be used to mimic the functionality of special 578 * administrative accounts (e.g., "cn=Directory Manager" in many directories). 579 * The map that is returned may be altered if desired. 580 * 581 * @return A map containing DNs and passwords of additional users that will 582 * be allowed to bind to the server, even if their entries do not 583 * exist in the data set. 584 */ 585 public Map<DN,byte[]> getAdditionalBindCredentials() 586 { 587 return additionalBindCredentials; 588 } 589 590 591 592 /** 593 * Adds an additional bind DN and password combination that can be used to 594 * bind to the server, even if the corresponding entry does not exist in the 595 * data set. This can be used to mimic the functionality of special 596 * administrative accounts (e.g., "cn=Directory Manager" in many directories). 597 * If a password has already been defined for the given DN, then it will be 598 * replaced with the newly-supplied password. 599 * 600 * @param dn The bind DN to allow. It must not be {@code null} or 601 * represent the null DN. 602 * @param password The password for the provided bind DN. It must not be 603 * {@code null} or empty. 604 * 605 * @throws LDAPException If there is a problem with the provided bind DN or 606 * password. 607 */ 608 public void addAdditionalBindCredentials(final String dn, 609 final String password) 610 throws LDAPException 611 { 612 addAdditionalBindCredentials(dn, StaticUtils.getBytes(password)); 613 } 614 615 616 617 /** 618 * Adds an additional bind DN and password combination that can be used to 619 * bind to the server, even if the corresponding entry does not exist in the 620 * data set. This can be used to mimic the functionality of special 621 * administrative accounts (e.g., "cn=Directory Manager" in many directories). 622 * If a password has already been defined for the given DN, then it will be 623 * replaced with the newly-supplied password. 624 * 625 * @param dn The bind DN to allow. It must not be {@code null} or 626 * represent the null DN. 627 * @param password The password for the provided bind DN. It must not be 628 * {@code null} or empty. 629 * 630 * @throws LDAPException If there is a problem with the provided bind DN or 631 * password. 632 */ 633 public void addAdditionalBindCredentials(final String dn, 634 final byte[] password) 635 throws LDAPException 636 { 637 if (dn == null) 638 { 639 throw new LDAPException(ResultCode.PARAM_ERROR, 640 ERR_MEM_DS_CFG_NULL_ADDITIONAL_BIND_DN.get()); 641 } 642 643 final DN parsedDN = new DN(dn, schema); 644 if (parsedDN.isNullDN()) 645 { 646 throw new LDAPException(ResultCode.PARAM_ERROR, 647 ERR_MEM_DS_CFG_NULL_ADDITIONAL_BIND_DN.get()); 648 } 649 650 if ((password == null) || (password.length == 0)) 651 { 652 throw new LDAPException(ResultCode.PARAM_ERROR, 653 ERR_MEM_DS_CFG_NULL_ADDITIONAL_BIND_PW.get()); 654 } 655 656 additionalBindCredentials.put(parsedDN, password); 657 } 658 659 660 661 /** 662 * Retrieves the object that should be used to handle any errors encountered 663 * while attempting to interact with a client, if defined. 664 * 665 * @return The object that should be used to handle any errors encountered 666 * while attempting to interact with a client, or {@code null} if no 667 * exception handler should be used. 668 */ 669 public LDAPListenerExceptionHandler getListenerExceptionHandler() 670 { 671 return exceptionHandler; 672 } 673 674 675 676 /** 677 * Specifies the LDAP listener exception handler that the server should use to 678 * handle any errors encountered while attempting to interact with a client. 679 * 680 * @param exceptionHandler The LDAP listener exception handler that the 681 * server should use to handle any errors 682 * encountered while attempting to interact with a 683 * client. It may be {@code null} if no exception 684 * handler should be used. 685 */ 686 public void setListenerExceptionHandler( 687 final LDAPListenerExceptionHandler exceptionHandler) 688 { 689 this.exceptionHandler = exceptionHandler; 690 } 691 692 693 694 /** 695 * Retrieves the schema that should be used by the server, if defined. If a 696 * schema is defined, then it will be used to validate entries and determine 697 * which matching rules should be used for various types of matching 698 * operations. 699 * 700 * @return The schema that should be used by the server, or {@code null} if 701 * no schema should be used. 702 */ 703 public Schema getSchema() 704 { 705 return schema; 706 } 707 708 709 710 /** 711 * Specifies the schema that should be used by the server. If a schema is 712 * defined, then it will be used to validate entries and determine which 713 * matching rules should be used for various types of matching operations. 714 * 715 * @param schema The schema that should be used by the server. It may be 716 * {@code null} if no schema should be used. 717 */ 718 public void setSchema(final Schema schema) 719 { 720 this.schema = schema; 721 } 722 723 724 725 /** 726 * Indicates whether the server should reject attribute values which violate 727 * the constraints of the associated syntax. This setting will be ignored if 728 * a {@code null} schema is in place. 729 * 730 * @return {@code true} if the server should reject attribute values which 731 * violate the constraints of the associated syntax, or {@code false} 732 * if not. 733 */ 734 public boolean enforceAttributeSyntaxCompliance() 735 { 736 return enforceAttributeSyntaxCompliance; 737 } 738 739 740 741 /** 742 * Specifies whether the server should reject attribute values which violate 743 * the constraints of the associated syntax. This setting will be ignored if 744 * a {@code null} schema is in place. 745 * 746 * @param enforceAttributeSyntaxCompliance Indicates whether the server 747 * should reject attribute values 748 * which violate the constraints of 749 * the associated syntax. 750 */ 751 public void setEnforceAttributeSyntaxCompliance( 752 final boolean enforceAttributeSyntaxCompliance) 753 { 754 this.enforceAttributeSyntaxCompliance = enforceAttributeSyntaxCompliance; 755 } 756 757 758 759 /** 760 * Indicates whether the server should reject entries which do not contain 761 * exactly one structural object class. This setting will be ignored if a 762 * {@code null} schema is in place. 763 * 764 * @return {@code true} if the server should reject entries which do not 765 * contain exactly one structural object class, or {@code false} if 766 * it should allow entries which do not have any structural class or 767 * that have multiple structural classes. 768 */ 769 public boolean enforceSingleStructuralObjectClass() 770 { 771 return enforceSingleStructuralObjectClass; 772 } 773 774 775 776 /** 777 * Specifies whether the server should reject entries which do not contain 778 * exactly one structural object class. This setting will be ignored if a 779 * {@code null} schema is in place. 780 * 781 * @param enforceSingleStructuralObjectClass Indicates whether the server 782 * should reject entries which do 783 * not contain exactly one 784 * structural object class. 785 */ 786 public void setEnforceSingleStructuralObjectClass( 787 final boolean enforceSingleStructuralObjectClass) 788 { 789 this.enforceSingleStructuralObjectClass = 790 enforceSingleStructuralObjectClass; 791 } 792 793 794 795 /** 796 * Retrieves the log handler that should be used to record access log messages 797 * about operations processed by the server, if any. 798 * 799 * @return The log handler that should be used to record access log messages 800 * about operations processed by the server, or {@code null} if no 801 * access logging should be performed. 802 */ 803 public Handler getAccessLogHandler() 804 { 805 return accessLogHandler; 806 } 807 808 809 810 /** 811 * Specifies the log handler that should be used to record access log messages 812 * about operations processed by the server. 813 * 814 * @param accessLogHandler The log handler that should be used to record 815 * access log messages about operations processed by 816 * the server. It may be {@code null} if no access 817 * logging should be performed. 818 */ 819 public void setAccessLogHandler(final Handler accessLogHandler) 820 { 821 this.accessLogHandler = accessLogHandler; 822 } 823 824 825 826 /** 827 * Retrieves the log handler that should be used to record detailed messages 828 * about LDAP communication to and from the server, which may be useful for 829 * debugging purposes. 830 * 831 * @return The log handler that should be used to record detailed 832 * protocol-level debug messages about LDAP communication to and from 833 * the server, or {@code null} if no debug logging should be 834 * performed. 835 */ 836 public Handler getLDAPDebugLogHandler() 837 { 838 return ldapDebugLogHandler; 839 } 840 841 842 843 /** 844 * Specifies the log handler that should be used to record detailed messages 845 * about LDAP communication to and from the server, which may be useful for 846 * debugging purposes. 847 * 848 * @param ldapDebugLogHandler The log handler that should be used to record 849 * detailed messages about LDAP communication to 850 * and from the server. It may be {@code null} 851 * if no LDAP debug logging should be performed. 852 */ 853 public void setLDAPDebugLogHandler(final Handler ldapDebugLogHandler) 854 { 855 this.ldapDebugLogHandler = ldapDebugLogHandler; 856 } 857 858 859 860 /** 861 * Retrieves the path to a file to be written with generated code that may 862 * be used to construct the requests processed by the server. 863 * 864 * @return The path to a file to be written with generated code that may be 865 * used to construct the requests processed by the server, or 866 * {@code null} if no code log should be written. 867 */ 868 public String getCodeLogPath() 869 { 870 return codeLogPath; 871 } 872 873 874 875 /** 876 * Indicates whether the code log should include sample code for processing 877 * the generated requests. This will only be used if {@link #getCodeLogPath} 878 * returns a non-{@code null} value. 879 * 880 * @return {@code false} if the code log should only include code that 881 * corresponds to requests received from clients, or {@code true} if 882 * the code log should also include sample code for processing the 883 * generated requests and interpreting the results. 884 */ 885 public boolean includeRequestProcessingInCodeLog() 886 { 887 return includeRequestProcessingInCodeLog; 888 } 889 890 891 892 /** 893 * Specifies information about code logging that should be performed by the 894 * server, if any. 895 * 896 * @param codeLogPath The path to the file to which a code log should 897 * be written. It may be {@code null} if no code 898 * log should be written. 899 * @param includeProcessing Indicates whether to include sample code that 900 * demonstrates how to process the requests and 901 * interpret the results. This will only be 902 * used if the {@code codeLogPath} argument is 903 * non-{@code null}. 904 */ 905 public void setCodeLogDetails(final String codeLogPath, 906 final boolean includeProcessing) 907 { 908 this.codeLogPath = codeLogPath; 909 includeRequestProcessingInCodeLog = includeProcessing; 910 } 911 912 913 914 /** 915 * Retrieves a list of the operation interceptors that may be used to 916 * intercept and transform requests before they are processed by the in-memory 917 * directory server, and/or to intercept and transform responses before they 918 * are returned to the client. The contents of the list may be altered by the 919 * caller. 920 * 921 * @return An updatable list of the operation interceptors that may be used 922 * to intercept and transform requests and/or responses. 923 */ 924 public List<InMemoryOperationInterceptor> getOperationInterceptors() 925 { 926 return operationInterceptors; 927 } 928 929 930 931 /** 932 * Adds the provided operation interceptor to the list of operation 933 * interceptors that may be used to transform requests before they are 934 * processed by the in-memory directory server, and/or to transform responses 935 * before they are returned to the client. 936 * 937 * @param interceptor The operation interceptor that should be invoked in 938 * the course of processing requests and responses. 939 */ 940 public void addInMemoryOperationInterceptor( 941 final InMemoryOperationInterceptor interceptor) 942 { 943 operationInterceptors.add(interceptor); 944 } 945 946 947 948 /** 949 * Retrieves a list of the extended operation handlers that may be used to 950 * process extended operations in the server. The contents of the list may 951 * be altered by the caller. 952 * 953 * @return An updatable list of the extended operation handlers that may be 954 * used to process extended operations in the server. 955 */ 956 public List<InMemoryExtendedOperationHandler> getExtendedOperationHandlers() 957 { 958 return extendedOperationHandlers; 959 } 960 961 962 963 /** 964 * Adds the provided extended operation handler for use by the server for 965 * processing certain types of extended operations. 966 * 967 * @param handler The extended operation handler that should be used by the 968 * server for processing certain types of extended 969 * operations. 970 */ 971 public void addExtendedOperationHandler( 972 final InMemoryExtendedOperationHandler handler) 973 { 974 extendedOperationHandlers.add(handler); 975 } 976 977 978 979 /** 980 * Retrieves a list of the SASL bind handlers that may be used to process 981 * SASL bind requests in the server. The contents of the list may be altered 982 * by the caller. 983 * 984 * @return An updatable list of the SASL bind handlers that may be used to 985 * process SASL bind requests in the server. 986 */ 987 public List<InMemorySASLBindHandler> getSASLBindHandlers() 988 { 989 return saslBindHandlers; 990 } 991 992 993 994 /** 995 * Adds the provided SASL bind handler for use by the server for processing 996 * certain types of SASL bind requests. 997 * 998 * @param handler The SASL bind handler that should be used by the server 999 * for processing certain types of SASL bind requests. 1000 */ 1001 public void addSASLBindHandler(final InMemorySASLBindHandler handler) 1002 { 1003 saslBindHandlers.add(handler); 1004 } 1005 1006 1007 1008 /** 1009 * Indicates whether the server should automatically generate operational 1010 * attributes (including entryDN, entryUUID, creatorsName, createTimestamp, 1011 * modifiersName, modifyTimestamp, and subschemaSubentry) for entries in the 1012 * server. 1013 * 1014 * @return {@code true} if the server should automatically generate 1015 * operational attributes for entries in the server, or {@code false} 1016 * if not. 1017 */ 1018 public boolean generateOperationalAttributes() 1019 { 1020 return generateOperationalAttributes; 1021 } 1022 1023 1024 1025 /** 1026 * Specifies whether the server should automatically generate operational 1027 * attributes (including entryDN, entryUUID, creatorsName, createTimestamp, 1028 * modifiersName, modifyTimestamp, and subschemaSubentry) for entries in the 1029 * server. 1030 * 1031 * @param generateOperationalAttributes Indicates whether the server should 1032 * automatically generate operational 1033 * attributes for entries in the 1034 * server. 1035 */ 1036 public void setGenerateOperationalAttributes( 1037 final boolean generateOperationalAttributes) 1038 { 1039 this.generateOperationalAttributes = generateOperationalAttributes; 1040 } 1041 1042 1043 1044 /** 1045 * Retrieves the maximum number of changelog entries that the server should 1046 * maintain. 1047 * 1048 * @return The maximum number of changelog entries that the server should 1049 * maintain, or 0 if the server should not maintain a changelog. 1050 */ 1051 public int getMaxChangeLogEntries() 1052 { 1053 return maxChangeLogEntries; 1054 } 1055 1056 1057 1058 /** 1059 * Specifies the maximum number of changelog entries that the server should 1060 * maintain. A value less than or equal to zero indicates that the server 1061 * should not attempt to maintain a changelog. 1062 * 1063 * @param maxChangeLogEntries The maximum number of changelog entries that 1064 * the server should maintain. 1065 */ 1066 public void setMaxChangeLogEntries(final int maxChangeLogEntries) 1067 { 1068 if (maxChangeLogEntries < 0) 1069 { 1070 this.maxChangeLogEntries = 0; 1071 } 1072 else 1073 { 1074 this.maxChangeLogEntries = maxChangeLogEntries; 1075 } 1076 } 1077 1078 1079 1080 /** 1081 * Retrieves the maximum number of concurrent connections that the server will 1082 * allow. If a client tries to establish a new connection while the server 1083 * already has the maximum number of concurrent connections, then the new 1084 * connection will be rejected. Note that if the server is configured with 1085 * multiple listeners, then each listener will be allowed to have up to this 1086 * number of connections. 1087 * 1088 * @return The maximum number of concurrent connections that the server will 1089 * allow, or zero if no limit should be enforced. 1090 */ 1091 public int getMaxConnections() 1092 { 1093 return maxConnections; 1094 } 1095 1096 1097 1098 /** 1099 * Specifies the maximum number of concurrent connections that the server will 1100 * allow. If a client tries to establish a new connection while the server 1101 * already has the maximum number of concurrent connections, then the new 1102 * connection will be rejected. Note that if the server is configured with 1103 * multiple listeners, then each listener will be allowed to have up to this 1104 * number of connections. 1105 * 1106 * @param maxConnections The maximum number of concurrent connections that 1107 * the server will allow. A value that is less than 1108 * or equal to zero indicates no limit. 1109 */ 1110 public void setMaxConnections(final int maxConnections) 1111 { 1112 if (maxConnections > 0) 1113 { 1114 this.maxConnections = maxConnections; 1115 } 1116 else 1117 { 1118 this.maxConnections = 0; 1119 } 1120 } 1121 1122 1123 1124 /** 1125 * Retrieves the maximum number of entries that the server should return in 1126 * any search operation. 1127 * 1128 * @return The maximum number of entries that the server should return in any 1129 * search operation, or zero if no limit should be enforced. 1130 */ 1131 public int getMaxSizeLimit() 1132 { 1133 return maxSizeLimit; 1134 } 1135 1136 1137 1138 /** 1139 * Specifies the maximum number of entries that the server should return in 1140 * any search operation. A value less than or equal to zero indicates that no 1141 * maximum limit should be enforced. 1142 * 1143 * @param maxSizeLimit The maximum number of entries that the server should 1144 * return in any search operation. 1145 */ 1146 public void setMaxSizeLimit(final int maxSizeLimit) 1147 { 1148 if (maxSizeLimit > 0) 1149 { 1150 this.maxSizeLimit = maxSizeLimit; 1151 } 1152 else 1153 { 1154 this.maxSizeLimit = 0; 1155 } 1156 } 1157 1158 1159 1160 /** 1161 * Retrieves a list containing the names or OIDs of the attribute types for 1162 * which to maintain an equality index to improve the performance of certain 1163 * kinds of searches. 1164 * 1165 * @return A list containing the names or OIDs of the attribute types for 1166 * which to maintain an equality index to improve the performance of 1167 * certain kinds of searches, or an empty list if no equality indexes 1168 * should be created. 1169 */ 1170 public List<String> getEqualityIndexAttributes() 1171 { 1172 return equalityIndexAttributes; 1173 } 1174 1175 1176 1177 /** 1178 * Specifies the names or OIDs of the attribute types for which to maintain an 1179 * equality index to improve the performance of certain kinds of searches. 1180 * 1181 * @param equalityIndexAttributes The names or OIDs of the attributes for 1182 * which to maintain an equality index to 1183 * improve the performance of certain kinds 1184 * of searches. It may be {@code null} or 1185 * empty to indicate that no equality indexes 1186 * should be maintained. 1187 */ 1188 public void setEqualityIndexAttributes( 1189 final String... equalityIndexAttributes) 1190 { 1191 setEqualityIndexAttributes(StaticUtils.toList(equalityIndexAttributes)); 1192 } 1193 1194 1195 1196 /** 1197 * Specifies the names or OIDs of the attribute types for which to maintain an 1198 * equality index to improve the performance of certain kinds of searches. 1199 * 1200 * @param equalityIndexAttributes The names or OIDs of the attributes for 1201 * which to maintain an equality index to 1202 * improve the performance of certain kinds 1203 * of searches. It may be {@code null} or 1204 * empty to indicate that no equality indexes 1205 * should be maintained. 1206 */ 1207 public void setEqualityIndexAttributes( 1208 final Collection<String> equalityIndexAttributes) 1209 { 1210 this.equalityIndexAttributes.clear(); 1211 if (equalityIndexAttributes != null) 1212 { 1213 this.equalityIndexAttributes.addAll(equalityIndexAttributes); 1214 } 1215 } 1216 1217 1218 1219 /** 1220 * Retrieves the names of the attributes for which referential integrity 1221 * should be maintained. If referential integrity is to be provided and an 1222 * entry is removed, then any other entries containing one of the specified 1223 * attributes with a value equal to the DN of the entry that was removed, then 1224 * that value will also be removed. Similarly, if an entry is moved or 1225 * renamed, then any references to that entry in one of the specified 1226 * attributes will be updated to reflect the new DN. 1227 * 1228 * @return The names of the attributes for which referential integrity should 1229 * be maintained, or an empty set if referential integrity should not 1230 * be maintained for any attributes. 1231 */ 1232 public Set<String> getReferentialIntegrityAttributes() 1233 { 1234 return referentialIntegrityAttributes; 1235 } 1236 1237 1238 1239 /** 1240 * Specifies the names of the attributes for which referential integrity 1241 * should be maintained. If referential integrity is to be provided and an 1242 * entry is removed, then any other entries containing one of the specified 1243 * attributes with a value equal to the DN of the entry that was removed, then 1244 * that value will also be removed. Similarly, if an entry is moved or 1245 * renamed, then any references to that entry in one of the specified 1246 * attributes will be updated to reflect the new DN. 1247 * 1248 * @param referentialIntegrityAttributes The names of the attributes for 1249 * which referential integrity should 1250 * be maintained. The values of 1251 * these attributes should be DNs. 1252 * It may be {@code null} or empty if 1253 * referential integrity should not 1254 * be maintained. 1255 */ 1256 public void setReferentialIntegrityAttributes( 1257 final String... referentialIntegrityAttributes) 1258 { 1259 setReferentialIntegrityAttributes( 1260 StaticUtils.toList(referentialIntegrityAttributes)); 1261 } 1262 1263 1264 1265 /** 1266 * Specifies the names of the attributes for which referential integrity 1267 * should be maintained. If referential integrity is to be provided and an 1268 * entry is removed, then any other entries containing one of the specified 1269 * attributes with a value equal to the DN of the entry that was removed, then 1270 * that value will also be removed. Similarly, if an entry is moved or 1271 * renamed, then any references to that entry in one of the specified 1272 * attributes will be updated to reflect the new DN. 1273 * 1274 * @param referentialIntegrityAttributes The names of the attributes for 1275 * which referential integrity should 1276 * be maintained. The values of 1277 * these attributes should be DNs. 1278 * It may be {@code null} or empty if 1279 * referential integrity should not 1280 * be maintained. 1281 */ 1282 public void setReferentialIntegrityAttributes( 1283 final Collection<String> referentialIntegrityAttributes) 1284 { 1285 this.referentialIntegrityAttributes.clear(); 1286 if (referentialIntegrityAttributes != null) 1287 { 1288 this.referentialIntegrityAttributes.addAll( 1289 referentialIntegrityAttributes); 1290 } 1291 } 1292 1293 1294 1295 /** 1296 * Retrieves the vendor name value to report in the server root DSE. 1297 * 1298 * @return The vendor name value to report in the server root DSE, or 1299 * {@code null} if no vendor name should appear. 1300 */ 1301 public String getVendorName() 1302 { 1303 return vendorName; 1304 } 1305 1306 1307 1308 /** 1309 * Specifies the vendor name value to report in the server root DSE. 1310 * 1311 * @param vendorName The vendor name value to report in the server root DSE. 1312 * It may be {@code null} if no vendor name should appear. 1313 */ 1314 public void setVendorName(final String vendorName) 1315 { 1316 this.vendorName = vendorName; 1317 } 1318 1319 1320 1321 /** 1322 * Retrieves the vendor version value to report in the server root DSE. 1323 * 1324 * @return The vendor version value to report in the server root DSE, or 1325 * {@code null} if no vendor version should appear. 1326 */ 1327 public String getVendorVersion() 1328 { 1329 return vendorVersion; 1330 } 1331 1332 1333 1334 /** 1335 * Specifies the vendor version value to report in the server root DSE. 1336 * 1337 * @param vendorVersion The vendor version value to report in the server 1338 * root DSE. It may be {@code null} if no vendor 1339 * version should appear. 1340 */ 1341 public void setVendorVersion(final String vendorVersion) 1342 { 1343 this.vendorVersion = vendorVersion; 1344 } 1345 1346 1347 1348 /** 1349 * Retrieves a predefined entry that should always be returned as the 1350 * in-memory directory server's root DSE, if defined. 1351 * 1352 * @return A predefined entry that should always be returned as the in-memory 1353 * directory server's root DSE, or {@code null} if the root DSE 1354 * should be dynamically generated. 1355 */ 1356 public ReadOnlyEntry getRootDSEEntry() 1357 { 1358 return rootDSEEntry; 1359 } 1360 1361 1362 1363 /** 1364 * Specifies an entry that should always be returned as the in-memory 1365 * directory server's root DSE. Note that if a specific root DSE entry is 1366 * provided, then 1367 * 1368 * @param rootDSEEntry An entry that should always be returned as the 1369 * in-memory directory server's root DSE, or 1370 * {@code null} to indicate that the root DSE should be 1371 * dynamically generated. 1372 */ 1373 public void setRootDSEEntry(final Entry rootDSEEntry) 1374 { 1375 if (rootDSEEntry == null) 1376 { 1377 this.rootDSEEntry = null; 1378 return; 1379 } 1380 1381 final Entry e = rootDSEEntry.duplicate(); 1382 e.setDN(""); 1383 this.rootDSEEntry = new ReadOnlyEntry(e); 1384 } 1385 1386 1387 1388 /** 1389 * Parses the provided set of strings as DNs. 1390 * 1391 * @param dnStrings The array of strings to be parsed as DNs. 1392 * @param schema The schema to use to generate the normalized 1393 * representations of the DNs, if available. 1394 * 1395 * @return The array of parsed DNs. 1396 * 1397 * @throws LDAPException If any of the provided strings cannot be parsed as 1398 * DNs. 1399 */ 1400 private static DN[] parseDNs(final Schema schema, final String... dnStrings) 1401 throws LDAPException 1402 { 1403 if (dnStrings == null) 1404 { 1405 return null; 1406 } 1407 1408 final DN[] dns = new DN[dnStrings.length]; 1409 for (int i=0; i < dns.length; i++) 1410 { 1411 dns[i] = new DN(dnStrings[i], schema); 1412 } 1413 return dns; 1414 } 1415 1416 1417 1418 /** 1419 * Retrieves a string representation of this in-memory directory server 1420 * configuration. 1421 * 1422 * @return A string representation of this in-memory directory server 1423 * configuration. 1424 */ 1425 @Override() 1426 public String toString() 1427 { 1428 final StringBuilder buffer = new StringBuilder(); 1429 toString(buffer); 1430 return buffer.toString(); 1431 } 1432 1433 1434 1435 /** 1436 * Appends a string representation of this in-memory directory server 1437 * configuration to the provided buffer. 1438 * 1439 * @param buffer The buffer to which the string representation should be 1440 * appended. 1441 */ 1442 public void toString(final StringBuilder buffer) 1443 { 1444 buffer.append("InMemoryDirectoryServerConfig(baseDNs={"); 1445 1446 for (int i=0; i < baseDNs.length; i++) 1447 { 1448 if (i > 0) 1449 { 1450 buffer.append(", "); 1451 } 1452 1453 buffer.append('\''); 1454 baseDNs[i].toString(buffer); 1455 buffer.append('\''); 1456 } 1457 buffer.append('}'); 1458 1459 buffer.append(", listenerConfigs={"); 1460 1461 final Iterator<InMemoryListenerConfig> listenerCfgIterator = 1462 listenerConfigs.iterator(); 1463 while(listenerCfgIterator.hasNext()) 1464 { 1465 listenerCfgIterator.next().toString(buffer); 1466 if (listenerCfgIterator.hasNext()) 1467 { 1468 buffer.append(", "); 1469 } 1470 } 1471 buffer.append('}'); 1472 1473 buffer.append(", schemaProvided="); 1474 buffer.append((schema != null)); 1475 buffer.append(", enforceAttributeSyntaxCompliance="); 1476 buffer.append(enforceAttributeSyntaxCompliance); 1477 buffer.append(", enforceSingleStructuralObjectClass="); 1478 buffer.append(enforceSingleStructuralObjectClass); 1479 1480 if (! additionalBindCredentials.isEmpty()) 1481 { 1482 buffer.append(", additionalBindDNs={"); 1483 1484 final Iterator<DN> bindDNIterator = 1485 additionalBindCredentials.keySet().iterator(); 1486 while (bindDNIterator.hasNext()) 1487 { 1488 buffer.append('\''); 1489 bindDNIterator.next().toString(buffer); 1490 buffer.append('\''); 1491 if (bindDNIterator.hasNext()) 1492 { 1493 buffer.append(", "); 1494 } 1495 } 1496 buffer.append('}'); 1497 } 1498 1499 if (! equalityIndexAttributes.isEmpty()) 1500 { 1501 buffer.append(", equalityIndexAttributes={"); 1502 1503 final Iterator<String> attrIterator = equalityIndexAttributes.iterator(); 1504 while (attrIterator.hasNext()) 1505 { 1506 buffer.append('\''); 1507 buffer.append(attrIterator.next()); 1508 buffer.append('\''); 1509 if (attrIterator.hasNext()) 1510 { 1511 buffer.append(", "); 1512 } 1513 } 1514 buffer.append('}'); 1515 } 1516 1517 if (! referentialIntegrityAttributes.isEmpty()) 1518 { 1519 buffer.append(", referentialIntegrityAttributes={"); 1520 1521 final Iterator<String> attrIterator = 1522 referentialIntegrityAttributes.iterator(); 1523 while (attrIterator.hasNext()) 1524 { 1525 buffer.append('\''); 1526 buffer.append(attrIterator.next()); 1527 buffer.append('\''); 1528 if (attrIterator.hasNext()) 1529 { 1530 buffer.append(", "); 1531 } 1532 } 1533 buffer.append('}'); 1534 } 1535 1536 buffer.append(", generateOperationalAttributes="); 1537 buffer.append(generateOperationalAttributes); 1538 1539 if (maxChangeLogEntries > 0) 1540 { 1541 buffer.append(", maxChangelogEntries="); 1542 buffer.append(maxChangeLogEntries); 1543 } 1544 1545 buffer.append(", maxConnections="); 1546 buffer.append(maxConnections); 1547 buffer.append(", maxSizeLimit="); 1548 buffer.append(maxSizeLimit); 1549 1550 if (! extendedOperationHandlers.isEmpty()) 1551 { 1552 buffer.append(", extendedOperationHandlers={"); 1553 1554 final Iterator<InMemoryExtendedOperationHandler> 1555 handlerIterator = extendedOperationHandlers.iterator(); 1556 while (handlerIterator.hasNext()) 1557 { 1558 buffer.append(handlerIterator.next().toString()); 1559 if (handlerIterator.hasNext()) 1560 { 1561 buffer.append(", "); 1562 } 1563 } 1564 buffer.append('}'); 1565 } 1566 1567 if (! saslBindHandlers.isEmpty()) 1568 { 1569 buffer.append(", saslBindHandlers={"); 1570 1571 final Iterator<InMemorySASLBindHandler> 1572 handlerIterator = saslBindHandlers.iterator(); 1573 while (handlerIterator.hasNext()) 1574 { 1575 buffer.append(handlerIterator.next().toString()); 1576 if (handlerIterator.hasNext()) 1577 { 1578 buffer.append(", "); 1579 } 1580 } 1581 buffer.append('}'); 1582 } 1583 1584 if (accessLogHandler != null) 1585 { 1586 buffer.append(", accessLogHandlerClass='"); 1587 buffer.append(accessLogHandler.getClass().getName()); 1588 buffer.append('\''); 1589 } 1590 1591 if (ldapDebugLogHandler != null) 1592 { 1593 buffer.append(", ldapDebugLogHandlerClass='"); 1594 buffer.append(ldapDebugLogHandler.getClass().getName()); 1595 buffer.append('\''); 1596 } 1597 1598 if (codeLogPath != null) 1599 { 1600 buffer.append(", codeLogPath='"); 1601 buffer.append(codeLogPath); 1602 buffer.append("', includeRequestProcessingInCodeLog="); 1603 buffer.append(includeRequestProcessingInCodeLog); 1604 } 1605 1606 if (exceptionHandler != null) 1607 { 1608 buffer.append(", listenerExceptionHandlerClass='"); 1609 buffer.append(exceptionHandler.getClass().getName()); 1610 buffer.append('\''); 1611 } 1612 1613 if (vendorName != null) 1614 { 1615 buffer.append(", vendorName='"); 1616 buffer.append(vendorName); 1617 buffer.append('\''); 1618 } 1619 1620 if (vendorVersion != null) 1621 { 1622 buffer.append(", vendorVersion='"); 1623 buffer.append(vendorVersion); 1624 buffer.append('\''); 1625 } 1626 1627 buffer.append(')'); 1628 } 1629}