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