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