001 /*
002 * Copyright 2011-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2011-2016 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.listener;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Arrays;
027 import java.util.Collection;
028 import java.util.EnumSet;
029 import java.util.HashSet;
030 import java.util.Iterator;
031 import java.util.LinkedHashMap;
032 import java.util.List;
033 import java.util.Map;
034 import java.util.Set;
035 import java.util.logging.Handler;
036
037 import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
038 import com.unboundid.ldap.sdk.DN;
039 import com.unboundid.ldap.sdk.Entry;
040 import com.unboundid.ldap.sdk.LDAPException;
041 import com.unboundid.ldap.sdk.OperationType;
042 import com.unboundid.ldap.sdk.ReadOnlyEntry;
043 import com.unboundid.ldap.sdk.ResultCode;
044 import com.unboundid.ldap.sdk.Version;
045 import com.unboundid.ldap.sdk.schema.Schema;
046 import com.unboundid.util.Mutable;
047 import com.unboundid.util.NotExtensible;
048 import com.unboundid.util.StaticUtils;
049 import com.unboundid.util.ThreadSafety;
050 import com.unboundid.util.ThreadSafetyLevel;
051
052 import 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)
099 public 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 }