001 /*
002 * Copyright 2011-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2011-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.listener;
022
023
024
025 import java.net.InetAddress;
026 import java.util.ArrayList;
027 import java.util.Arrays;
028 import java.util.Collection;
029 import java.util.Collections;
030 import java.util.LinkedHashMap;
031 import java.util.List;
032 import java.util.Map;
033 import javax.net.SocketFactory;
034
035 import com.unboundid.asn1.ASN1OctetString;
036 import com.unboundid.ldap.listener.interceptor.
037 InMemoryOperationInterceptorRequestHandler;
038 import com.unboundid.ldap.protocol.AddRequestProtocolOp;
039 import com.unboundid.ldap.protocol.AddResponseProtocolOp;
040 import com.unboundid.ldap.protocol.BindRequestProtocolOp;
041 import com.unboundid.ldap.protocol.BindResponseProtocolOp;
042 import com.unboundid.ldap.protocol.CompareRequestProtocolOp;
043 import com.unboundid.ldap.protocol.CompareResponseProtocolOp;
044 import com.unboundid.ldap.protocol.DeleteRequestProtocolOp;
045 import com.unboundid.ldap.protocol.DeleteResponseProtocolOp;
046 import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp;
047 import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp;
048 import com.unboundid.ldap.protocol.LDAPMessage;
049 import com.unboundid.ldap.protocol.ModifyRequestProtocolOp;
050 import com.unboundid.ldap.protocol.ModifyResponseProtocolOp;
051 import com.unboundid.ldap.protocol.ModifyDNRequestProtocolOp;
052 import com.unboundid.ldap.protocol.ModifyDNResponseProtocolOp;
053 import com.unboundid.ldap.protocol.SearchRequestProtocolOp;
054 import com.unboundid.ldap.protocol.SearchResultDoneProtocolOp;
055 import com.unboundid.ldap.sdk.AddRequest;
056 import com.unboundid.ldap.sdk.Attribute;
057 import com.unboundid.ldap.sdk.BindRequest;
058 import com.unboundid.ldap.sdk.BindResult;
059 import com.unboundid.ldap.sdk.CompareRequest;
060 import com.unboundid.ldap.sdk.CompareResult;
061 import com.unboundid.ldap.sdk.Control;
062 import com.unboundid.ldap.sdk.DeleteRequest;
063 import com.unboundid.ldap.sdk.DereferencePolicy;
064 import com.unboundid.ldap.sdk.DN;
065 import com.unboundid.ldap.sdk.Entry;
066 import com.unboundid.ldap.sdk.ExtendedRequest;
067 import com.unboundid.ldap.sdk.ExtendedResult;
068 import com.unboundid.ldap.sdk.Filter;
069 import com.unboundid.ldap.sdk.InternalSDKHelper;
070 import com.unboundid.ldap.sdk.LDAPConnection;
071 import com.unboundid.ldap.sdk.LDAPConnectionOptions;
072 import com.unboundid.ldap.sdk.LDAPConnectionPool;
073 import com.unboundid.ldap.sdk.LDAPException;
074 import com.unboundid.ldap.sdk.LDAPInterface;
075 import com.unboundid.ldap.sdk.LDAPResult;
076 import com.unboundid.ldap.sdk.LDAPSearchException;
077 import com.unboundid.ldap.sdk.Modification;
078 import com.unboundid.ldap.sdk.ModifyRequest;
079 import com.unboundid.ldap.sdk.ModifyDNRequest;
080 import com.unboundid.ldap.sdk.PLAINBindRequest;
081 import com.unboundid.ldap.sdk.ReadOnlyAddRequest;
082 import com.unboundid.ldap.sdk.ReadOnlyCompareRequest;
083 import com.unboundid.ldap.sdk.ReadOnlyDeleteRequest;
084 import com.unboundid.ldap.sdk.ReadOnlyModifyRequest;
085 import com.unboundid.ldap.sdk.ReadOnlyModifyDNRequest;
086 import com.unboundid.ldap.sdk.ReadOnlySearchRequest;
087 import com.unboundid.ldap.sdk.ResultCode;
088 import com.unboundid.ldap.sdk.RootDSE;
089 import com.unboundid.ldap.sdk.SearchRequest;
090 import com.unboundid.ldap.sdk.SearchResult;
091 import com.unboundid.ldap.sdk.SearchResultEntry;
092 import com.unboundid.ldap.sdk.SearchResultListener;
093 import com.unboundid.ldap.sdk.SearchResultReference;
094 import com.unboundid.ldap.sdk.SearchScope;
095 import com.unboundid.ldap.sdk.SimpleBindRequest;
096 import com.unboundid.ldap.sdk.schema.Schema;
097 import com.unboundid.ldif.LDIFException;
098 import com.unboundid.ldif.LDIFReader;
099 import com.unboundid.ldif.LDIFWriter;
100 import com.unboundid.util.ByteStringBuffer;
101 import com.unboundid.util.Debug;
102 import com.unboundid.util.Mutable;
103 import com.unboundid.util.StaticUtils;
104 import com.unboundid.util.ThreadSafety;
105 import com.unboundid.util.ThreadSafetyLevel;
106 import com.unboundid.util.Validator;
107
108 import static com.unboundid.ldap.listener.ListenerMessages.*;
109
110
111
112 /**
113 * This class provides a utility that may be used to create a simple LDAP server
114 * instance that will hold all of its information in memory. It is intended to
115 * be very easy to use, particularly as an embeddable server for testing
116 * directory-enabled applications. It can be easily created, configured,
117 * populated, and shut down with only a few lines of code, and it provides a
118 * number of convenience methods that can be very helpful in writing test cases
119 * that validate the content of the server.
120 * <BR><BR>
121 * Some notes about the capabilities of this server:
122 * <UL>
123 * <LI>It provides reasonably complete support for add, compare, delete,
124 * modify, modify DN (including new superior and subtree move/rename),
125 * search, and unbind operations.</LI>
126 * <LI>It will accept abandon requests, but will not do anything with
127 * them.</LI>
128 * <LI>It provides support for simple bind operations, and for the SASL PLAIN
129 * mechanism. It also provides an API that can be used to add support for
130 * additional SASL mechanisms.</LI>
131 * <LI>It provides support for the password modify, StartTLS, and "who am I?"
132 * extended operations, as well as an API that can be used to add support
133 * for additional types of extended operations.</LI>
134 * <LI>It provides support for the LDAP assertions, authorization identity,
135 * don't use copy, manage DSA IT, permissive modify, pre-read, post-read,
136 * proxied authorization v1 and v2, server-side sort, simple paged
137 * results, LDAP subentries, subtree delete, and virtual list view request
138 * controls.</LI>
139 * <LI>It supports the use of schema (if provided), but it does not currently
140 * allow updating the schema on the fly.</LI>
141 * <LI>It has the ability to maintain a log of operations processed, either
142 * as a simple access log or a more detailed LDAP debug log.</LI>
143 * <LI>It has the ability to maintain an LDAP-accessible changelog.</LI>
144 * <LI>It provides an option to generate a number of operational attributes,
145 * including entryDN, entryUUID, creatorsName, createTimestamp,
146 * modifiersName, modifyTimestamp, and subschemaSubentry.</LI>
147 * <LI>It provides support for referential integrity, in which case specified
148 * attributes whose values are DNs may be updated if the entries they
149 * reference are deleted or renamed.</LI>
150 * <LI>It provides methods for importing data from and exporting data to LDIF
151 * files, and it has the ability to capture a point-in-time snapshot of
152 * the data (including changelog information) that may be restored at any
153 * point.</LI>
154 * <LI>It implements the {@link LDAPInterface} interface, which means that in
155 * many cases it can be used as a drop-in replacement for an
156 * {@link LDAPConnection}.</LI>
157 * </UL>
158 * <BR><BR>
159 * In order to create an in-memory directory server instance, you should first
160 * create an {@link InMemoryDirectoryServerConfig} object with the desired
161 * settings. Then use that configuration object to initialize the directory
162 * server instance, and call the {@link #startListening} method to start
163 * accepting connections from LDAP clients. The {@link #getConnection} and
164 * {@link #getConnectionPool} methods may be used to obtain connections to the
165 * server and you can also manually create connections using the information
166 * obtained via the {@link #getListenAddress}, {@link #getListenPort}, and
167 * {@link #getClientSocketFactory} methods. When the server is no longer
168 * needed, the {@link #shutDown} method should be used to stop the server. Any
169 * number of in-memory directory server instances can be created and running in
170 * a single JVM at any time, and many of the methods provided in this class can
171 * be used without the server running if operations are to be performed using
172 * only method calls rather than via LDAP clients.
173 * <BR><BR>
174 * <H2>Example</H2>
175 * The following example demonstrates the process that can be used to create,
176 * start, and use an in-memory directory server instance, including support for
177 * secure communication using both SSL and StartTLS:
178 * <PRE>
179 * // Create a base configuration for the server.
180 * InMemoryDirectoryServerConfig config =
181 * new InMemoryDirectoryServerConfig("dc=example,dc=com");
182 * config.addAdditionalBindCredentials("cn=Directory Manager",
183 * "password");
184 *
185 * // Update the configuration to support LDAP (with StartTLS) and LDAPS
186 * // listeners.
187 * final SSLUtil serverSSLUtil = new SSLUtil(
188 * new KeyStoreKeyManager(serverKeyStorePath, serverKeyStorePIN, "JKS",
189 * "server-cert"),
190 * new TrustStoreTrustManager(serverTrustStorePath));
191 * final SSLUtil clientSSLUtil = new SSLUtil(
192 * new TrustStoreTrustManager(clientTrustStorePath));
193 * config.setListenerConfigs(
194 * InMemoryListenerConfig.createLDAPConfig("LDAP", // Listener name
195 * null, // Listen address. (null = listen on all interfaces)
196 * 0, // Listen port (0 = automatically choose an available port)
197 * serverSSLUtil.createSSLSocketFactory()), // StartTLS factory
198 * InMemoryListenerConfig.createLDAPSConfig("LDAPS", // Listener name
199 * null, // Listen address. (null = listen on all interfaces)
200 * 0, // Listen port (0 = automatically choose an available port)
201 * serverSSLUtil.createSSLServerSocketFactory(), // Server factory
202 * clientSSLUtil.createSSLSocketFactory())); // Client factory
203 *
204 * // Create and start the server instance and populate it with an initial set
205 * // of data from an LDIF file.
206 * InMemoryDirectoryServer server = new InMemoryDirectoryServer(config);
207 * server.importFromLDIF(true, ldifFilePath);
208 *
209 * // Start the server so it will accept client connections.
210 * server.startListening();
211 *
212 * // Get an unencrypted connection to the server's LDAP listener, then use
213 * // StartTLS to secure that connection. Make sure the connection is usable
214 * // by retrieving the server root DSE.
215 * LDAPConnection connection = server.getConnection("LDAP");
216 * connection.processExtendedOperation(new StartTLSExtendedRequest(
217 * clientSSLUtil.createSSLContext()));
218 * LDAPTestUtils.assertEntryExists(connection, "");
219 * connection.close();
220 *
221 * // Establish an SSL-based connection to the LDAPS listener, and make sure
222 * // that connection is also usable.
223 * connection = server.getConnection("LDAPS");
224 * LDAPTestUtils.assertEntryExists(connection, "");
225 * connection.close();
226 *
227 * // Shut down the server so that it will no longer accept client
228 * // connections, and close all existing connections.
229 * server.shutDown(true);
230 * </PRE>
231 */
232 @Mutable()
233 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
234 public final class InMemoryDirectoryServer
235 implements LDAPInterface
236 {
237 // The in-memory request handler that will be used for the server.
238 private final InMemoryRequestHandler inMemoryHandler;
239
240 // The set of listeners that have been configured for this server, mapped by
241 // listener name.
242 private final Map<String,LDAPListener> listeners;
243
244 // The set of configurations for all the LDAP listeners to be used.
245 private final Map<String,LDAPListenerConfig> ldapListenerConfigs;
246
247 // The set of client socket factories associated with each of the listeners.
248 private final Map<String,SocketFactory> clientSocketFactories;
249
250 // A read-only representation of the configuration used to create this
251 // in-memory directory server.
252 private final ReadOnlyInMemoryDirectoryServerConfig config;
253
254
255
256 /**
257 * Creates a very simple instance of an in-memory directory server with the
258 * specified set of base DNs. It will not use a well-defined schema, and will
259 * pick a listen port at random.
260 *
261 * @param baseDNs The base DNs to use for the server. It must not be
262 * {@code null} or empty.
263 *
264 * @throws LDAPException If a problem occurs while attempting to initialize
265 * the server.
266 */
267 public InMemoryDirectoryServer(final String... baseDNs)
268 throws LDAPException
269 {
270 this(new InMemoryDirectoryServerConfig(baseDNs));
271 }
272
273
274
275 /**
276 * Creates a new instance of an in-memory directory server with the provided
277 * configuration.
278 *
279 * @param cfg The configuration to use for the server. It must not be
280 * {@code null}.
281 *
282 * @throws LDAPException If a problem occurs while trying to initialize the
283 * directory server with the provided configuration.
284 */
285 public InMemoryDirectoryServer(final InMemoryDirectoryServerConfig cfg)
286 throws LDAPException
287 {
288 Validator.ensureNotNull(cfg);
289
290 config = new ReadOnlyInMemoryDirectoryServerConfig(cfg);
291 inMemoryHandler = new InMemoryRequestHandler(config);
292
293 LDAPListenerRequestHandler requestHandler = inMemoryHandler;
294
295 if (config.getAccessLogHandler() != null)
296 {
297 requestHandler = new AccessLogRequestHandler(config.getAccessLogHandler(),
298 requestHandler);
299 }
300
301 if (config.getLDAPDebugLogHandler() != null)
302 {
303 requestHandler = new LDAPDebuggerRequestHandler(
304 config.getLDAPDebugLogHandler(), requestHandler);
305 }
306
307 if (! config.getOperationInterceptors().isEmpty())
308 {
309 requestHandler = new InMemoryOperationInterceptorRequestHandler(
310 config.getOperationInterceptors(), requestHandler);
311 }
312
313
314 final List<InMemoryListenerConfig> listenerConfigs =
315 config.getListenerConfigs();
316
317 listeners = new LinkedHashMap<String,LDAPListener>(listenerConfigs.size());
318 ldapListenerConfigs =
319 new LinkedHashMap<String,LDAPListenerConfig>(listenerConfigs.size());
320 clientSocketFactories =
321 new LinkedHashMap<String,SocketFactory>(listenerConfigs.size());
322
323 for (final InMemoryListenerConfig c : listenerConfigs)
324 {
325 final String name = StaticUtils.toLowerCase(c.getListenerName());
326
327 final LDAPListenerRequestHandler listenerRequestHandler;
328 if (c.getStartTLSSocketFactory() == null)
329 {
330 listenerRequestHandler = requestHandler;
331 }
332 else
333 {
334 listenerRequestHandler =
335 new StartTLSRequestHandler(c.getStartTLSSocketFactory(),
336 requestHandler);
337 }
338
339 final LDAPListenerConfig listenerCfg = new LDAPListenerConfig(
340 c.getListenPort(), listenerRequestHandler);
341 listenerCfg.setExceptionHandler(config.getListenerExceptionHandler());
342 listenerCfg.setListenAddress(c.getListenAddress());
343 listenerCfg.setServerSocketFactory(c.getServerSocketFactory());
344
345 ldapListenerConfigs.put(name, listenerCfg);
346
347 if (c.getClientSocketFactory() != null)
348 {
349 clientSocketFactories.put(name, c.getClientSocketFactory());
350 }
351 }
352 }
353
354
355
356 /**
357 * Attempts to start listening for client connections on all configured
358 * listeners. Any listeners that are already running will be unaffected.
359 *
360 * @throws LDAPException If a problem occurs while attempting to create any
361 * of the configured listeners. Even if an exception
362 * is thrown, then as many listeners as possible will
363 * be started.
364 */
365 public synchronized void startListening()
366 throws LDAPException
367 {
368 final ArrayList<String> messages = new ArrayList<String>(listeners.size());
369
370 for (final Map.Entry<String,LDAPListenerConfig> cfgEntry :
371 ldapListenerConfigs.entrySet())
372 {
373 final String name = cfgEntry.getKey();
374
375 if (listeners.containsKey(name))
376 {
377 // This listener is already running.
378 continue;
379 }
380
381 final LDAPListenerConfig listenerConfig = cfgEntry.getValue();
382 final LDAPListener listener = new LDAPListener(listenerConfig);
383
384 try
385 {
386 listener.startListening();
387 listenerConfig.setListenPort(listener.getListenPort());
388 listeners.put(name, listener);
389 }
390 catch (final Exception e)
391 {
392 Debug.debugException(e);
393 messages.add(ERR_MEM_DS_START_FAILED.get(name,
394 StaticUtils.getExceptionMessage(e)));
395 }
396 }
397
398 if (! messages.isEmpty())
399 {
400 throw new LDAPException(ResultCode.LOCAL_ERROR,
401 StaticUtils.concatenateStrings(messages));
402 }
403 }
404
405
406
407 /**
408 * Attempts to start listening for client connections on the specified
409 * listener. If the listener is already running, then it will be unaffected.
410 *
411 * @param listenerName The name of the listener to be started. It must not
412 * be {@code null}.
413 *
414 * @throws LDAPException If a problem occurs while attempting to start the
415 * requested listener.
416 */
417 public synchronized void startListening(final String listenerName)
418 throws LDAPException
419 {
420 // If the listener is already running, then there's nothing to do.
421 final String name = StaticUtils .toLowerCase(listenerName);
422 if (listeners.containsKey(name))
423 {
424 return;
425 }
426
427 // Get the configuration to use for the listener.
428 final LDAPListenerConfig listenerConfig = ldapListenerConfigs.get(name);
429 if (listenerConfig == null)
430 {
431 throw new LDAPException(ResultCode.PARAM_ERROR,
432 ERR_MEM_DS_NO_SUCH_LISTENER.get(listenerName));
433 }
434
435
436 final LDAPListener listener = new LDAPListener(listenerConfig);
437
438 try
439 {
440 listener.startListening();
441 listenerConfig.setListenPort(listener.getListenPort());
442 listeners.put(name, listener);
443 }
444 catch (final Exception e)
445 {
446 Debug.debugException(e);
447 throw new LDAPException(ResultCode.LOCAL_ERROR,
448 ERR_MEM_DS_START_FAILED.get(name,
449 StaticUtils.getExceptionMessage(e)),
450 e);
451 }
452 }
453
454
455
456 /**
457 * Shuts down all configured listeners. Any listeners that are already
458 * stopped will be unaffected.
459 *
460 * @param closeExistingConnections Indicates whether to close all existing
461 * connections, or merely to stop accepting
462 * new connections.
463 */
464 public synchronized void shutDown(final boolean closeExistingConnections)
465 {
466 for (final LDAPListener l : listeners.values())
467 {
468 try
469 {
470 l.shutDown(closeExistingConnections);
471 }
472 catch (final Exception e)
473 {
474 Debug.debugException(e);
475 }
476 }
477
478 listeners.clear();
479 }
480
481
482
483 /**
484 * Shuts down the specified listener. If there is no such listener defined,
485 * or if the specified listener is not running, then no action will be taken.
486 *
487 * @param listenerName The name of the listener to be shut down.
488 * It must not be {@code null}.
489 * @param closeExistingConnections Indicates whether to close all existing
490 * connections, or merely to stop accepting
491 * new connections.
492 */
493 public synchronized void shutDown(final String listenerName,
494 final boolean closeExistingConnections)
495 {
496 final String name = StaticUtils.toLowerCase(listenerName);
497 final LDAPListener listener = listeners.remove(name);
498 if (listener != null)
499 {
500 listener.shutDown(closeExistingConnections);
501 }
502 }
503
504
505
506 /**
507 * Attempts to restart all listeners defined in the server. All running
508 * listeners will be stopped, and all configured listeners will be started.
509 *
510 * @throws LDAPException If a problem occurs while attempting to restart any
511 * of the listeners. Even if an exception is thrown,
512 * as many listeners as possible will be started.
513 */
514 public synchronized void restartServer()
515 throws LDAPException
516 {
517 shutDown(true);
518
519 try
520 {
521 Thread.sleep(100L);
522 }
523 catch (final Exception e)
524 {
525 Debug.debugException(e);
526 }
527
528 startListening();
529 }
530
531
532
533 /**
534 * Attempts to restart the specified listener. If it is running, it will be
535 * stopped. It will then be started.
536 *
537 * @param listenerName The name of the listener to be restarted. It must
538 * not be {@code null}.
539 *
540 * @throws LDAPException If a problem occurs while attempting to restart the
541 * specified listener.
542 */
543 public synchronized void restartListener(final String listenerName)
544 throws LDAPException
545 {
546 shutDown(listenerName, true);
547
548 try
549 {
550 Thread.sleep(100L);
551 }
552 catch (final Exception e)
553 {
554 Debug.debugException(e);
555 }
556
557 startListening(listenerName);
558 }
559
560
561
562 /**
563 * Retrieves a read-only representation of the configuration used to create
564 * this in-memory directory server instance.
565 *
566 * @return A read-only representation of the configuration used to create
567 * this in-memory directory server instance.
568 */
569 public ReadOnlyInMemoryDirectoryServerConfig getConfig()
570 {
571 return config;
572 }
573
574
575
576 /**
577 * Retrieves the in-memory request handler that is used to perform the real
578 * server processing.
579 *
580 * @return The in-memory request handler that is used to perform the real
581 * server processing.
582 */
583 InMemoryRequestHandler getInMemoryRequestHandler()
584 {
585 return inMemoryHandler;
586 }
587
588
589
590 /**
591 * Creates a point-in-time snapshot of the information contained in this
592 * in-memory directory server instance. It may be restored using the
593 * {@link #restoreSnapshot} method.
594 * <BR><BR>
595 * This method may be used regardless of whether the server is listening for
596 * client connections.
597 *
598 * @return The snapshot created based on the current content of this
599 * in-memory directory server instance.
600 */
601 public InMemoryDirectoryServerSnapshot createSnapshot()
602 {
603 return inMemoryHandler.createSnapshot();
604 }
605
606
607
608 /**
609 * Restores the this in-memory directory server instance to match the content
610 * it held at the time the snapshot was created.
611 * <BR><BR>
612 * This method may be used regardless of whether the server is listening for
613 * client connections.
614 *
615 * @param snapshot The snapshot to be restored. It must not be
616 * {@code null}.
617 */
618 public void restoreSnapshot(final InMemoryDirectoryServerSnapshot snapshot)
619 {
620 inMemoryHandler.restoreSnapshot(snapshot);
621 }
622
623
624
625 /**
626 * Retrieves the list of base DNs configured for use by the server.
627 *
628 * @return The list of base DNs configured for use by the server.
629 */
630 public List<DN> getBaseDNs()
631 {
632 return inMemoryHandler.getBaseDNs();
633 }
634
635
636
637 /**
638 * Attempts to establish a client connection to the server. If multiple
639 * listeners are configured, then it will attempt to establish a connection to
640 * the first configured listener that is running.
641 *
642 * @return The client connection that has been established.
643 *
644 * @throws LDAPException If a problem is encountered while attempting to
645 * create the connection.
646 */
647 public LDAPConnection getConnection()
648 throws LDAPException
649 {
650 return getConnection(null, null);
651 }
652
653
654
655 /**
656 * Attempts to establish a client connection to the server.
657 *
658 * @param options The connection options to use when creating the
659 * connection. It may be {@code null} if a default set of
660 * options should be used.
661 *
662 * @return The client connection that has been established.
663 *
664 * @throws LDAPException If a problem is encountered while attempting to
665 * create the connection.
666 */
667 public LDAPConnection getConnection(final LDAPConnectionOptions options)
668 throws LDAPException
669 {
670 return getConnection(null, options);
671 }
672
673
674
675 /**
676 * Attempts to establish a client connection to the specified listener.
677 *
678 * @param listenerName The name of the listener to which to establish the
679 * connection. It may be {@code null} if a connection
680 * should be established to the first available
681 * listener.
682 *
683 * @return The client connection that has been established.
684 *
685 * @throws LDAPException If a problem is encountered while attempting to
686 * create the connection.
687 */
688 public LDAPConnection getConnection(final String listenerName)
689 throws LDAPException
690 {
691 return getConnection(listenerName, null);
692 }
693
694
695
696 /**
697 * Attempts to establish a client connection to the specified listener.
698 *
699 * @param listenerName The name of the listener to which to establish the
700 * connection. It may be {@code null} if a connection
701 * should be established to the first available
702 * listener.
703 * @param options The set of LDAP connection options to use for the
704 * connection that is created.
705 *
706 * @return The client connection that has been established.
707 *
708 * @throws LDAPException If a problem is encountered while attempting to
709 * create the connection.
710 */
711 public synchronized LDAPConnection getConnection(final String listenerName,
712 final LDAPConnectionOptions options)
713 throws LDAPException
714 {
715 final LDAPListenerConfig listenerConfig;
716 final SocketFactory clientSocketFactory;
717
718 if (listenerName == null)
719 {
720 final String name = getFirstListenerName();
721 if (name == null)
722 {
723 throw new LDAPException(ResultCode.CONNECT_ERROR,
724 ERR_MEM_DS_GET_CONNECTION_NO_LISTENERS.get());
725 }
726
727 listenerConfig = ldapListenerConfigs.get(name);
728 clientSocketFactory = clientSocketFactories.get(name);
729 }
730 else
731 {
732 final String name = StaticUtils.toLowerCase(listenerName);
733 if (! listeners.containsKey(name))
734 {
735 throw new LDAPException(ResultCode.CONNECT_ERROR,
736 ERR_MEM_DS_GET_CONNECTION_LISTENER_NOT_RUNNING.get(listenerName));
737 }
738
739 listenerConfig = ldapListenerConfigs.get(name);
740 clientSocketFactory = clientSocketFactories.get(name);
741 }
742
743 String hostAddress;
744 final InetAddress listenAddress = listenerConfig.getListenAddress();
745 if ((listenAddress == null) || (listenAddress.isAnyLocalAddress()))
746 {
747 try
748 {
749 hostAddress = InetAddress.getLocalHost().getHostAddress();
750 }
751 catch (final Exception e)
752 {
753 Debug.debugException(e);
754 hostAddress = "127.0.0.1";
755 }
756 }
757 else
758 {
759 hostAddress = listenAddress.getHostAddress();
760 }
761
762 return new LDAPConnection(clientSocketFactory, options, hostAddress,
763 listenerConfig.getListenPort());
764 }
765
766
767
768 /**
769 * Attempts to establish a connection pool to the server with the specified
770 * maximum number of connections.
771 *
772 * @param maxConnections The maximum number of connections to maintain in
773 * the connection pool. It must be greater than or
774 * equal to one.
775 *
776 * @return The connection pool that has been created.
777 *
778 * @throws LDAPException If a problem occurs while attempting to create the
779 * connection pool.
780 */
781 public LDAPConnectionPool getConnectionPool(final int maxConnections)
782 throws LDAPException
783 {
784 return getConnectionPool(null, null, 1, maxConnections);
785 }
786
787
788
789 /**
790 * Attempts to establish a connection pool to the server with the provided
791 * settings.
792 *
793 * @param listenerName The name of the listener to which the
794 * connections should be established.
795 * @param options The connection options to use when creating
796 * connections for use in the pool. It may be
797 * {@code null} if a default set of options should
798 * be used.
799 * @param initialConnections The initial number of connections to establish
800 * in the connection pool. It must be greater
801 * than or equal to one.
802 * @param maxConnections The maximum number of connections to maintain
803 * in the connection pool. It must be greater
804 * than or equal to the initial number of
805 * connections.
806 *
807 * @return The connection pool that has been created.
808 *
809 * @throws LDAPException If a problem occurs while attempting to create the
810 * connection pool.
811 */
812 public LDAPConnectionPool getConnectionPool(final String listenerName,
813 final LDAPConnectionOptions options,
814 final int initialConnections,
815 final int maxConnections)
816 throws LDAPException
817 {
818 final LDAPConnection conn = getConnection(listenerName, options);
819 return new LDAPConnectionPool(conn, initialConnections, maxConnections);
820 }
821
822
823
824 /**
825 * Retrieves the configured listen address for the first active listener, if
826 * defined.
827 *
828 * @return The configured listen address for the first active listener, or
829 * {@code null} if that listener does not have an
830 * explicitly-configured listen address or there are no active
831 * listeners.
832 */
833 public InetAddress getListenAddress()
834 {
835 return getListenAddress(null);
836 }
837
838
839
840 /**
841 * Retrieves the configured listen address for the specified listener, if
842 * defined.
843 *
844 * @param listenerName The name of the listener for which to retrieve the
845 * listen address. It may be {@code null} in order to
846 * obtain the listen address for the first active
847 * listener.
848 *
849 * @return The configured listen address for the specified listener, or
850 * {@code null} if there is no such listener or the listener does not
851 * have an explicitly-configured listen address.
852 */
853 public synchronized InetAddress getListenAddress(final String listenerName)
854 {
855 final String name;
856 if (listenerName == null)
857 {
858 name = getFirstListenerName();
859 }
860 else
861 {
862 name = StaticUtils.toLowerCase(listenerName);
863 }
864
865 final LDAPListenerConfig listenerCfg = ldapListenerConfigs.get(name);
866 if (listenerCfg == null)
867 {
868 return null;
869 }
870 else
871 {
872 return listenerCfg.getListenAddress();
873 }
874 }
875
876
877
878 /**
879 * Retrieves the configured listen port for the first active listener.
880 *
881 * @return The configured listen port for the first active listener, or -1 if
882 * there are no active listeners.
883 */
884 public int getListenPort()
885 {
886 return getListenPort(null);
887 }
888
889
890
891 /**
892 * Retrieves the configured listen port for the specified listener, if
893 * available.
894 *
895 * @param listenerName The name of the listener for which to retrieve the
896 * listen port. It may be {@code null} in order to
897 * obtain the listen port for the first active
898 * listener.
899 *
900 * @return The configured listen port for the specified listener, or -1 if
901 * there is no such listener or the listener is not active.
902 */
903 public synchronized int getListenPort(final String listenerName)
904 {
905 final String name;
906 if (listenerName == null)
907 {
908 name = getFirstListenerName();
909 }
910 else
911 {
912 name = StaticUtils.toLowerCase(listenerName);
913 }
914
915 final LDAPListener listener = listeners.get(name);
916 if (listener == null)
917 {
918 return -1;
919 }
920 else
921 {
922 return listener.getListenPort();
923 }
924 }
925
926
927
928 /**
929 * Retrieves the configured client socket factory for the first active
930 * listener.
931 *
932 * @return The configured client socket factory for the first active
933 * listener, or {@code null} if that listener does not have an
934 * explicitly-configured socket factory or there are no active
935 * listeners.
936 */
937 public SocketFactory getClientSocketFactory()
938 {
939 return getClientSocketFactory(null);
940 }
941
942
943
944 /**
945 * Retrieves the configured client socket factory for the specified listener,
946 * if available.
947 *
948 * @param listenerName The name of the listener for which to retrieve the
949 * client socket factory. It may be {@code null} in
950 * order to obtain the client socket factory for the
951 * first active listener.
952 *
953 * @return The configured client socket factory for the specified listener,
954 * or {@code null} if there is no such listener or that listener does
955 * not have an explicitly-configured client socket factory.
956 */
957 public synchronized SocketFactory getClientSocketFactory(
958 final String listenerName)
959 {
960 final String name;
961 if (listenerName == null)
962 {
963 name = getFirstListenerName();
964 }
965 else
966 {
967 name = StaticUtils.toLowerCase(listenerName);
968 }
969
970 return clientSocketFactories.get(name);
971 }
972
973
974
975 /**
976 * Retrieves the name of the first running listener.
977 *
978 * @return The name of the first running listener, or {@code null} if there
979 * are no active listeners.
980 */
981 private String getFirstListenerName()
982 {
983 for (final Map.Entry<String,LDAPListenerConfig> e :
984 ldapListenerConfigs.entrySet())
985 {
986 final String name = e.getKey();
987 if (listeners.containsKey(name))
988 {
989 return name;
990 }
991 }
992
993 return null;
994 }
995
996
997
998 /**
999 * Retrieves the delay in milliseconds that the server should impose before
1000 * beginning processing for operations.
1001 *
1002 * @return The delay in milliseconds that the server should impose before
1003 * beginning processing for operations, or 0 if there should be no
1004 * delay inserted when processing operations.
1005 */
1006 public long getProcessingDelayMillis()
1007 {
1008 return inMemoryHandler.getProcessingDelayMillis();
1009 }
1010
1011
1012
1013 /**
1014 * Specifies the delay in milliseconds that the server should impose before
1015 * beginning processing for operations.
1016 *
1017 * @param processingDelayMillis The delay in milliseconds that the server
1018 * should impose before beginning processing
1019 * for operations. A value less than or equal
1020 * to zero may be used to indicate that there
1021 * should be no delay.
1022 */
1023 public void setProcessingDelayMillis(final long processingDelayMillis)
1024 {
1025 inMemoryHandler.setProcessingDelayMillis(processingDelayMillis);
1026 }
1027
1028
1029
1030 /**
1031 * Retrieves the number of entries currently held in the server. The count
1032 * returned will not include entries which are part of the changelog.
1033 * <BR><BR>
1034 * This method may be used regardless of whether the server is listening for
1035 * client connections.
1036 *
1037 * @return The number of entries currently held in the server.
1038 */
1039 public int countEntries()
1040 {
1041 return countEntries(false);
1042 }
1043
1044
1045
1046 /**
1047 * Retrieves the number of entries currently held in the server, optionally
1048 * including those entries which are part of the changelog.
1049 * <BR><BR>
1050 * This method may be used regardless of whether the server is listening for
1051 * client connections.
1052 *
1053 * @param includeChangeLog Indicates whether to include entries that are
1054 * part of the changelog in the count.
1055 *
1056 * @return The number of entries currently held in the server.
1057 */
1058 public int countEntries(final boolean includeChangeLog)
1059 {
1060 return inMemoryHandler.countEntries(includeChangeLog);
1061 }
1062
1063
1064
1065 /**
1066 * Retrieves the number of entries currently held in the server whose DN
1067 * matches or is subordinate to the provided base DN.
1068 * <BR><BR>
1069 * This method may be used regardless of whether the server is listening for
1070 * client connections.
1071 *
1072 * @param baseDN The base DN to use for the determination.
1073 *
1074 * @return The number of entries currently held in the server whose DN
1075 * matches or is subordinate to the provided base DN.
1076 *
1077 * @throws LDAPException If the provided string cannot be parsed as a valid
1078 * DN.
1079 */
1080 public int countEntriesBelow(final String baseDN)
1081 throws LDAPException
1082 {
1083 return inMemoryHandler.countEntriesBelow(baseDN);
1084 }
1085
1086
1087
1088 /**
1089 * Removes all entries currently held in the server. If a changelog is
1090 * enabled, then all changelog entries will also be cleared but the base
1091 * "cn=changelog" entry will be retained.
1092 * <BR><BR>
1093 * This method may be used regardless of whether the server is listening for
1094 * client connections.
1095 */
1096 public void clear()
1097 {
1098 inMemoryHandler.clear();
1099 }
1100
1101
1102
1103 /**
1104 * Reads entries from the specified LDIF file and adds them to the server,
1105 * optionally clearing any existing entries before beginning to add the new
1106 * entries. If an error is encountered while adding entries from LDIF then
1107 * the server will remain populated with the data it held before the import
1108 * attempt (even if the {@code clear} is given with a value of {@code true}).
1109 * <BR><BR>
1110 * This method may be used regardless of whether the server is listening for
1111 * client connections.
1112 *
1113 * @param clear Indicates whether to remove all existing entries prior to
1114 * adding entries read from LDIF.
1115 * @param path The path to the LDIF file from which the entries should be
1116 * read. It must not be {@code null}.
1117 *
1118 * @return The number of entries read from LDIF and added to the server.
1119 *
1120 * @throws LDAPException If a problem occurs while reading entries or adding
1121 * them to the server.
1122 */
1123 public int importFromLDIF(final boolean clear, final String path)
1124 throws LDAPException
1125 {
1126 final LDIFReader reader;
1127 try
1128 {
1129 reader = new LDIFReader(path);
1130 }
1131 catch (final Exception e)
1132 {
1133 Debug.debugException(e);
1134 throw new LDAPException(ResultCode.LOCAL_ERROR,
1135 ERR_MEM_DS_INIT_FROM_LDIF_CANNOT_CREATE_READER.get(path,
1136 StaticUtils.getExceptionMessage(e)),
1137 e);
1138 }
1139
1140 return importFromLDIF(clear, reader);
1141 }
1142
1143
1144
1145 /**
1146 * Reads entries from the provided LDIF reader and adds them to the server,
1147 * optionally clearing any existing entries before beginning to add the new
1148 * entries. If an error is encountered while adding entries from LDIF then
1149 * the server will remain populated with the data it held before the import
1150 * attempt (even if the {@code clear} is given with a value of {@code true}).
1151 * <BR><BR>
1152 * This method may be used regardless of whether the server is listening for
1153 * client connections.
1154 *
1155 * @param clear Indicates whether to remove all existing entries prior to
1156 * adding entries read from LDIF.
1157 * @param reader The LDIF reader to use to obtain the entries to be
1158 * imported.
1159 *
1160 * @return The number of entries read from LDIF and added to the server.
1161 *
1162 * @throws LDAPException If a problem occurs while reading entries or adding
1163 * them to the server.
1164 */
1165 public int importFromLDIF(final boolean clear, final LDIFReader reader)
1166 throws LDAPException
1167 {
1168 return inMemoryHandler.importFromLDIF(clear, reader);
1169 }
1170
1171
1172
1173 /**
1174 * Writes the current contents of the server in LDIF form to the specified
1175 * file.
1176 * <BR><BR>
1177 * This method may be used regardless of whether the server is listening for
1178 * client connections.
1179 *
1180 * @param path The path of the file to which the LDIF
1181 * entries should be written.
1182 * @param excludeGeneratedAttrs Indicates whether to exclude automatically
1183 * generated operational attributes like
1184 * entryUUID, entryDN, creatorsName, etc.
1185 * @param excludeChangeLog Indicates whether to exclude entries
1186 * contained in the changelog.
1187 *
1188 * @return The number of entries written to LDIF.
1189 *
1190 * @throws LDAPException If a problem occurs while writing entries to LDIF.
1191 */
1192 public int exportToLDIF(final String path,
1193 final boolean excludeGeneratedAttrs,
1194 final boolean excludeChangeLog)
1195 throws LDAPException
1196 {
1197 final LDIFWriter ldifWriter;
1198 try
1199 {
1200 ldifWriter = new LDIFWriter(path);
1201 }
1202 catch (final Exception e)
1203 {
1204 Debug.debugException(e);
1205 throw new LDAPException(ResultCode.LOCAL_ERROR,
1206 ERR_MEM_DS_EXPORT_TO_LDIF_CANNOT_CREATE_WRITER.get(path,
1207 StaticUtils.getExceptionMessage(e)),
1208 e);
1209 }
1210
1211 return exportToLDIF(ldifWriter, excludeGeneratedAttrs, excludeChangeLog,
1212 true);
1213 }
1214
1215
1216
1217 /**
1218 * Writes the current contents of the server in LDIF form using the provided
1219 * LDIF writer.
1220 * <BR><BR>
1221 * This method may be used regardless of whether the server is listening for
1222 * client connections.
1223 *
1224 * @param ldifWriter The LDIF writer to use when writing the
1225 * entries. It must not be {@code null}.
1226 * @param excludeGeneratedAttrs Indicates whether to exclude automatically
1227 * generated operational attributes like
1228 * entryUUID, entryDN, creatorsName, etc.
1229 * @param excludeChangeLog Indicates whether to exclude entries
1230 * contained in the changelog.
1231 * @param closeWriter Indicates whether the LDIF writer should be
1232 * closed after all entries have been written.
1233 *
1234 * @return The number of entries written to LDIF.
1235 *
1236 * @throws LDAPException If a problem occurs while writing entries to LDIF.
1237 */
1238 public int exportToLDIF(final LDIFWriter ldifWriter,
1239 final boolean excludeGeneratedAttrs,
1240 final boolean excludeChangeLog,
1241 final boolean closeWriter)
1242 throws LDAPException
1243 {
1244 return inMemoryHandler.exportToLDIF(ldifWriter, excludeGeneratedAttrs,
1245 excludeChangeLog, closeWriter);
1246 }
1247
1248
1249
1250 /**
1251 * {@inheritDoc}
1252 * <BR><BR>
1253 * This method may be used regardless of whether the server is listening for
1254 * client connections.
1255 */
1256 public RootDSE getRootDSE()
1257 throws LDAPException
1258 {
1259 return new RootDSE(inMemoryHandler.getEntry(""));
1260 }
1261
1262
1263
1264 /**
1265 * {@inheritDoc}
1266 * <BR><BR>
1267 * This method may be used regardless of whether the server is listening for
1268 * client connections.
1269 */
1270 public Schema getSchema()
1271 throws LDAPException
1272 {
1273 return inMemoryHandler.getSchema();
1274 }
1275
1276
1277
1278 /**
1279 * {@inheritDoc}
1280 * <BR><BR>
1281 * This method may be used regardless of whether the server is listening for
1282 * client connections.
1283 */
1284 public Schema getSchema(final String entryDN)
1285 throws LDAPException
1286 {
1287 return inMemoryHandler.getSchema();
1288 }
1289
1290
1291
1292 /**
1293 * {@inheritDoc}
1294 * <BR><BR>
1295 * This method may be used regardless of whether the server is listening for
1296 * client connections.
1297 */
1298 public SearchResultEntry getEntry(final String dn)
1299 throws LDAPException
1300 {
1301 return searchForEntry(dn, SearchScope.BASE,
1302 Filter.createPresenceFilter("objectClass"));
1303 }
1304
1305
1306
1307 /**
1308 * {@inheritDoc}
1309 * <BR><BR>
1310 * This method may be used regardless of whether the server is listening for
1311 * client connections, and regardless of whether search operations are
1312 * allowed in the server.
1313 */
1314 public SearchResultEntry getEntry(final String dn, final String... attributes)
1315 throws LDAPException
1316 {
1317 return searchForEntry(dn, SearchScope.BASE,
1318 Filter.createPresenceFilter("objectClass"), attributes);
1319 }
1320
1321
1322
1323 /**
1324 * {@inheritDoc}
1325 * <BR><BR>
1326 * This method may be used regardless of whether the server is listening for
1327 * client connections, and regardless of whether add operations are allowed in
1328 * the server.
1329 */
1330 public LDAPResult add(final String dn, final Attribute... attributes)
1331 throws LDAPException
1332 {
1333 return add(new AddRequest(dn, attributes));
1334 }
1335
1336
1337
1338 /**
1339 * {@inheritDoc}
1340 * <BR><BR>
1341 * This method may be used regardless of whether the server is listening for
1342 * client connections, and regardless of whether add operations are allowed in
1343 * the server.
1344 */
1345 public LDAPResult add(final String dn, final Collection<Attribute> attributes)
1346 throws LDAPException
1347 {
1348 return add(new AddRequest(dn, attributes));
1349 }
1350
1351
1352
1353 /**
1354 * {@inheritDoc}
1355 * <BR><BR>
1356 * This method may be used regardless of whether the server is listening for
1357 * client connections, and regardless of whether add operations are allowed in
1358 * the server.
1359 */
1360 public LDAPResult add(final Entry entry)
1361 throws LDAPException
1362 {
1363 return add(new AddRequest(entry));
1364 }
1365
1366
1367
1368 /**
1369 * {@inheritDoc}
1370 * <BR><BR>
1371 * This method may be used regardless of whether the server is listening for
1372 * client connections, and regardless of whether add operations are allowed in
1373 * the server.
1374 */
1375 public LDAPResult add(final String... ldifLines)
1376 throws LDIFException, LDAPException
1377 {
1378 return add(new AddRequest(ldifLines));
1379 }
1380
1381
1382
1383 /**
1384 * {@inheritDoc}
1385 * <BR><BR>
1386 * This method may be used regardless of whether the server is listening for
1387 * client connections, and regardless of whether add operations are allowed in
1388 * the server.
1389 */
1390 public LDAPResult add(final AddRequest addRequest)
1391 throws LDAPException
1392 {
1393 final ArrayList<Control> requestControlList =
1394 new ArrayList<Control>(addRequest.getControlList());
1395 requestControlList.add(new Control(
1396 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false));
1397
1398 final LDAPMessage responseMessage = inMemoryHandler.processAddRequest(1,
1399 new AddRequestProtocolOp(addRequest.getDN(),
1400 addRequest.getAttributes()),
1401 requestControlList);
1402
1403 final AddResponseProtocolOp addResponse =
1404 responseMessage.getAddResponseProtocolOp();
1405
1406 final LDAPResult ldapResult = new LDAPResult(responseMessage.getMessageID(),
1407 ResultCode.valueOf(addResponse.getResultCode()),
1408 addResponse.getDiagnosticMessage(), addResponse.getMatchedDN(),
1409 addResponse.getReferralURLs(), responseMessage.getControls());
1410
1411 switch (addResponse.getResultCode())
1412 {
1413 case ResultCode.SUCCESS_INT_VALUE:
1414 case ResultCode.NO_OPERATION_INT_VALUE:
1415 return ldapResult;
1416 default:
1417 throw new LDAPException(ldapResult);
1418 }
1419 }
1420
1421
1422
1423 /**
1424 * {@inheritDoc}
1425 * <BR><BR>
1426 * This method may be used regardless of whether the server is listening for
1427 * client connections, and regardless of whether add operations are allowed in
1428 * the server.
1429 */
1430 public LDAPResult add(final ReadOnlyAddRequest addRequest)
1431 throws LDAPException
1432 {
1433 return add(addRequest.duplicate());
1434 }
1435
1436
1437
1438 /**
1439 * Attempts to add all of the provided entries to the server. If a problem is
1440 * encountered while attempting to add any of the provided entries, then the
1441 * server will remain populated with the data it held before this method was
1442 * called.
1443 * <BR><BR>
1444 * This method may be used regardless of whether the server is listening for
1445 * client connections, and regardless of whether add operations are allowed in
1446 * the server.
1447 *
1448 * @param entries The entries to be added to the server.
1449 *
1450 * @throws LDAPException If a problem is encountered while attempting to add
1451 * any of the provided entries.
1452 */
1453 public void addEntries(final Entry... entries)
1454 throws LDAPException
1455 {
1456 addEntries(Arrays.asList(entries));
1457 }
1458
1459
1460
1461 /**
1462 * Attempts to add all of the provided entries to the server. If a problem is
1463 * encountered while attempting to add any of the provided entries, then the
1464 * server will remain populated with the data it held before this method was
1465 * called.
1466 * <BR><BR>
1467 * This method may be used regardless of whether the server is listening for
1468 * client connections, and regardless of whether add operations are allowed in
1469 * the server.
1470 *
1471 * @param entries The entries to be added to the server.
1472 *
1473 * @throws LDAPException If a problem is encountered while attempting to add
1474 * any of the provided entries.
1475 */
1476 public void addEntries(final List<? extends Entry> entries)
1477 throws LDAPException
1478 {
1479 inMemoryHandler.addEntries(entries);
1480 }
1481
1482
1483
1484 /**
1485 * Attempts to add a set of entries provided in LDIF form in which each
1486 * element of the provided array is a line of the LDIF representation, with
1487 * empty strings as separators between entries (as you would have for blank
1488 * lines in an LDIF file). If a problem is encountered while attempting to
1489 * add any of the provided entries, then the server will remain populated with
1490 * the data it held before this method was called.
1491 * <BR><BR>
1492 * This method may be used regardless of whether the server is listening for
1493 * client connections, and regardless of whether add operations are allowed in
1494 * the server.
1495 *
1496 * @param ldifEntryLines The lines comprising the LDIF representation of the
1497 * entries to be added.
1498 *
1499 * @throws LDAPException If a problem is encountered while attempting to add
1500 * any of the provided entries.
1501 */
1502 public void addEntries(final String... ldifEntryLines)
1503 throws LDAPException
1504 {
1505 final ByteStringBuffer buffer = new ByteStringBuffer();
1506 for (final String line : ldifEntryLines)
1507 {
1508 buffer.append(line);
1509 buffer.append(StaticUtils.EOL_BYTES);
1510 }
1511
1512 final ArrayList<Entry> entryList = new ArrayList<Entry>(10);
1513 final LDIFReader reader = new LDIFReader(buffer.asInputStream());
1514 while (true)
1515 {
1516 try
1517 {
1518 final Entry entry = reader.readEntry();
1519 if (entry == null)
1520 {
1521 break;
1522 }
1523 else
1524 {
1525 entryList.add(entry);
1526 }
1527 }
1528 catch (final Exception e)
1529 {
1530 Debug.debugException(e);
1531 throw new LDAPException(ResultCode.PARAM_ERROR,
1532 ERR_MEM_DS_ADD_ENTRIES_LDIF_PARSE_EXCEPTION.get(
1533 StaticUtils.getExceptionMessage(e)),
1534 e);
1535 }
1536 }
1537
1538 addEntries(entryList);
1539 }
1540
1541
1542
1543 /**
1544 * Processes a simple bind request with the provided DN and password. Note
1545 * that the bind processing will verify that the provided credentials are
1546 * valid, but it will not alter the server in any way.
1547 *
1548 * @param bindDN The bind DN for the bind operation.
1549 * @param password The password for the simple bind operation.
1550 *
1551 * @return The result of processing the bind operation.
1552 *
1553 * @throws LDAPException If the server rejects the bind request, or if a
1554 * problem occurs while sending the request or reading
1555 * the response.
1556 */
1557 public BindResult bind(final String bindDN, final String password)
1558 throws LDAPException
1559 {
1560 return bind(new SimpleBindRequest(bindDN, password));
1561 }
1562
1563
1564
1565 /**
1566 * Processes the provided bind request. Only simple and SASL PLAIN bind
1567 * requests are supported. Note that the bind processing will verify that the
1568 * provided credentials are valid, but it will not alter the server in any
1569 * way.
1570 *
1571 * @param bindRequest The bind request to be processed. It must not be
1572 * {@code null}.
1573 *
1574 * @return The result of processing the bind operation.
1575 *
1576 * @throws LDAPException If the server rejects the bind request, or if a
1577 * problem occurs while sending the request or reading
1578 * the response.
1579 */
1580 public BindResult bind(final BindRequest bindRequest)
1581 throws LDAPException
1582 {
1583 final ArrayList<Control> requestControlList =
1584 new ArrayList<Control>(bindRequest.getControlList());
1585 requestControlList.add(new Control(
1586 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false));
1587
1588 final BindRequestProtocolOp bindOp;
1589 if (bindRequest instanceof SimpleBindRequest)
1590 {
1591 final SimpleBindRequest r = (SimpleBindRequest) bindRequest;
1592 bindOp = new BindRequestProtocolOp(r.getBindDN(),
1593 r.getPassword().getValue());
1594 }
1595 else if (bindRequest instanceof PLAINBindRequest)
1596 {
1597 final PLAINBindRequest r = (PLAINBindRequest) bindRequest;
1598
1599 // Create the byte array that should comprise the credentials.
1600 final byte[] authZIDBytes = StaticUtils.getBytes(r.getAuthorizationID());
1601 final byte[] authNIDBytes = StaticUtils.getBytes(r.getAuthenticationID());
1602 final byte[] passwordBytes = r.getPasswordBytes();
1603
1604 final byte[] credBytes = new byte[2 + authZIDBytes.length +
1605 authNIDBytes.length + passwordBytes.length];
1606 System.arraycopy(authZIDBytes, 0, credBytes, 0, authZIDBytes.length);
1607
1608 int pos = authZIDBytes.length + 1;
1609 System.arraycopy(authNIDBytes, 0, credBytes, pos, authNIDBytes.length);
1610
1611 pos += authNIDBytes.length + 1;
1612 System.arraycopy(passwordBytes, 0, credBytes, pos, passwordBytes.length);
1613
1614 bindOp = new BindRequestProtocolOp(null, "PLAIN",
1615 new ASN1OctetString(credBytes));
1616 }
1617 else
1618 {
1619 throw new LDAPException(ResultCode.AUTH_METHOD_NOT_SUPPORTED,
1620 ERR_MEM_DS_UNSUPPORTED_BIND_TYPE.get());
1621 }
1622
1623 final LDAPMessage responseMessage = inMemoryHandler.processBindRequest(1,
1624 bindOp, requestControlList);
1625 final BindResponseProtocolOp bindResponse =
1626 responseMessage.getBindResponseProtocolOp();
1627
1628 final BindResult bindResult = new BindResult(new LDAPResult(
1629 responseMessage.getMessageID(),
1630 ResultCode.valueOf(bindResponse.getResultCode()),
1631 bindResponse.getDiagnosticMessage(), bindResponse.getMatchedDN(),
1632 bindResponse.getReferralURLs(), responseMessage.getControls()));
1633
1634 switch (bindResponse.getResultCode())
1635 {
1636 case ResultCode.SUCCESS_INT_VALUE:
1637 return bindResult;
1638 default:
1639 throw new LDAPException(bindResult);
1640 }
1641 }
1642
1643
1644
1645 /**
1646 * {@inheritDoc}
1647 * <BR><BR>
1648 * This method may be used regardless of whether the server is listening for
1649 * client connections, and regardless of whether compare operations are
1650 * allowed in the server.
1651 */
1652 public CompareResult compare(final String dn, final String attributeName,
1653 final String assertionValue)
1654 throws LDAPException
1655 {
1656 return compare(new CompareRequest(dn, attributeName, assertionValue));
1657 }
1658
1659
1660
1661 /**
1662 * {@inheritDoc}
1663 * <BR><BR>
1664 * This method may be used regardless of whether the server is listening for
1665 * client connections, and regardless of whether compare operations are
1666 * allowed in the server.
1667 */
1668 public CompareResult compare(final CompareRequest compareRequest)
1669 throws LDAPException
1670 {
1671 final ArrayList<Control> requestControlList =
1672 new ArrayList<Control>(compareRequest.getControlList());
1673 requestControlList.add(new Control(
1674 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false));
1675
1676 final LDAPMessage responseMessage = inMemoryHandler.processCompareRequest(1,
1677 new CompareRequestProtocolOp(compareRequest.getDN(),
1678 compareRequest.getAttributeName(),
1679 compareRequest.getRawAssertionValue()),
1680 requestControlList);
1681
1682 final CompareResponseProtocolOp compareResponse =
1683 responseMessage.getCompareResponseProtocolOp();
1684
1685 final LDAPResult compareResult = new LDAPResult(
1686 responseMessage.getMessageID(),
1687 ResultCode.valueOf(compareResponse.getResultCode()),
1688 compareResponse.getDiagnosticMessage(), compareResponse.getMatchedDN(),
1689 compareResponse.getReferralURLs(), responseMessage.getControls());
1690
1691 switch (compareResponse.getResultCode())
1692 {
1693 case ResultCode.COMPARE_TRUE_INT_VALUE:
1694 case ResultCode.COMPARE_FALSE_INT_VALUE:
1695 return new CompareResult(compareResult);
1696 default:
1697 throw new LDAPException(compareResult);
1698 }
1699 }
1700
1701
1702
1703 /**
1704 * {@inheritDoc}
1705 * <BR><BR>
1706 * This method may be used regardless of whether the server is listening for
1707 * client connections, and regardless of whether compare operations are
1708 * allowed in the server.
1709 */
1710 public CompareResult compare(final ReadOnlyCompareRequest compareRequest)
1711 throws LDAPException
1712 {
1713 return compare(compareRequest.duplicate());
1714 }
1715
1716
1717
1718 /**
1719 * {@inheritDoc}
1720 * <BR><BR>
1721 * This method may be used regardless of whether the server is listening for
1722 * client connections, and regardless of whether delete operations are
1723 * allowed in the server.
1724 */
1725 public LDAPResult delete(final String dn)
1726 throws LDAPException
1727 {
1728 return delete(new DeleteRequest(dn));
1729 }
1730
1731
1732
1733 /**
1734 * {@inheritDoc}
1735 * <BR><BR>
1736 * This method may be used regardless of whether the server is listening for
1737 * client connections, and regardless of whether delete operations are
1738 * allowed in the server.
1739 */
1740 public LDAPResult delete(final DeleteRequest deleteRequest)
1741 throws LDAPException
1742 {
1743 final ArrayList<Control> requestControlList =
1744 new ArrayList<Control>(deleteRequest.getControlList());
1745 requestControlList.add(new Control(
1746 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false));
1747
1748 final LDAPMessage responseMessage = inMemoryHandler.processDeleteRequest(1,
1749 new DeleteRequestProtocolOp(deleteRequest.getDN()),
1750 requestControlList);
1751
1752 final DeleteResponseProtocolOp deleteResponse =
1753 responseMessage.getDeleteResponseProtocolOp();
1754
1755 final LDAPResult ldapResult = new LDAPResult(responseMessage.getMessageID(),
1756 ResultCode.valueOf(deleteResponse.getResultCode()),
1757 deleteResponse.getDiagnosticMessage(), deleteResponse.getMatchedDN(),
1758 deleteResponse.getReferralURLs(), responseMessage.getControls());
1759
1760 switch (deleteResponse.getResultCode())
1761 {
1762 case ResultCode.SUCCESS_INT_VALUE:
1763 case ResultCode.NO_OPERATION_INT_VALUE:
1764 return ldapResult;
1765 default:
1766 throw new LDAPException(ldapResult);
1767 }
1768 }
1769
1770
1771
1772 /**
1773 * {@inheritDoc}
1774 * <BR><BR>
1775 * This method may be used regardless of whether the server is listening for
1776 * client connections, and regardless of whether delete operations are
1777 * allowed in the server.
1778 */
1779 public LDAPResult delete(final ReadOnlyDeleteRequest deleteRequest)
1780 throws LDAPException
1781 {
1782 return delete(deleteRequest.duplicate());
1783 }
1784
1785
1786
1787 /**
1788 * Attempts to delete the specified entry and all entries below it from the
1789 * server.
1790 * <BR><BR>
1791 * This method may be used regardless of whether the server is listening for
1792 * client connections, and regardless of whether compare operations are
1793 * allowed in the server.
1794 *
1795 * @param baseDN The DN of the entry to remove, along with all of its
1796 * subordinates.
1797 *
1798 * @return The number of entries removed from the server, or zero if the
1799 * specified entry was not found.
1800 *
1801 * @throws LDAPException If a problem is encountered while attempting to
1802 * remove the entries.
1803 */
1804 public int deleteSubtree(final String baseDN)
1805 throws LDAPException
1806 {
1807 return inMemoryHandler.deleteSubtree(baseDN);
1808 }
1809
1810
1811
1812 /**
1813 * Processes an extended request with the provided request OID. Note that
1814 * because some types of extended operations return unusual result codes under
1815 * "normal" conditions, the server may not always throw an exception for a
1816 * failed extended operation like it does for other types of operations. It
1817 * will throw an exception under conditions where there appears to be a
1818 * problem with the connection or the server to which the connection is
1819 * established, but there may be many circumstances in which an extended
1820 * operation is not processed correctly but this method does not throw an
1821 * exception. In the event that no exception is thrown, it is the
1822 * responsibility of the caller to interpret the result to determine whether
1823 * the operation was processed as expected.
1824 * <BR><BR>
1825 * This method may be used regardless of whether the server is listening for
1826 * client connections, and regardless of whether extended operations are
1827 * allowed in the server.
1828 *
1829 * @param requestOID The OID for the extended request to process. It must
1830 * not be {@code null}.
1831 *
1832 * @return The extended result object that provides information about the
1833 * result of the request processing. It may or may not indicate that
1834 * the operation was successful.
1835 *
1836 * @throws LDAPException If a problem occurs while sending the request or
1837 * reading the response.
1838 */
1839 public ExtendedResult processExtendedOperation(final String requestOID)
1840 throws LDAPException
1841 {
1842 Validator.ensureNotNull(requestOID);
1843
1844 return processExtendedOperation(new ExtendedRequest(requestOID));
1845 }
1846
1847
1848
1849 /**
1850 * Processes an extended request with the provided request OID and value.
1851 * Note that because some types of extended operations return unusual result
1852 * codes under "normal" conditions, the server may not always throw an
1853 * exception for a failed extended operation like it does for other types of
1854 * operations. It will throw an exception under conditions where there
1855 * appears to be a problem with the connection or the server to which the
1856 * connection is established, but there may be many circumstances in which an
1857 * extended operation is not processed correctly but this method does not
1858 * throw an exception. In the event that no exception is thrown, it is the
1859 * responsibility of the caller to interpret the result to determine whether
1860 * the operation was processed as expected.
1861 * <BR><BR>
1862 * This method may be used regardless of whether the server is listening for
1863 * client connections, and regardless of whether extended operations are
1864 * allowed in the server.
1865 *
1866 * @param requestOID The OID for the extended request to process. It must
1867 * not be {@code null}.
1868 * @param requestValue The encoded value for the extended request to
1869 * process. It may be {@code null} if there does not
1870 * need to be a value for the requested operation.
1871 *
1872 * @return The extended result object that provides information about the
1873 * result of the request processing. It may or may not indicate that
1874 * the operation was successful.
1875 *
1876 * @throws LDAPException If a problem occurs while sending the request or
1877 * reading the response.
1878 */
1879 public ExtendedResult processExtendedOperation(final String requestOID,
1880 final ASN1OctetString requestValue)
1881 throws LDAPException
1882 {
1883 Validator.ensureNotNull(requestOID);
1884
1885 return processExtendedOperation(new ExtendedRequest(requestOID,
1886 requestValue));
1887 }
1888
1889
1890
1891 /**
1892 * Processes the provided extended request. Note that because some types of
1893 * extended operations return unusual result codes under "normal" conditions,
1894 * the server may not always throw an exception for a failed extended
1895 * operation like it does for other types of operations. It will throw an
1896 * exception under conditions where there appears to be a problem with the
1897 * connection or the server to which the connection is established, but there
1898 * may be many circumstances in which an extended operation is not processed
1899 * correctly but this method does not throw an exception. In the event that
1900 * no exception is thrown, it is the responsibility of the caller to interpret
1901 * the result to determine whether the operation was processed as expected.
1902 * <BR><BR>
1903 * This method may be used regardless of whether the server is listening for
1904 * client connections, and regardless of whether extended operations are
1905 * allowed in the server.
1906 *
1907 * @param extendedRequest The extended request to be processed. It must not
1908 * be {@code null}.
1909 *
1910 * @return The extended result object that provides information about the
1911 * result of the request processing. It may or may not indicate that
1912 * the operation was successful.
1913 *
1914 * @throws LDAPException If a problem occurs while sending the request or
1915 * reading the response.
1916 */
1917 public ExtendedResult processExtendedOperation(
1918 final ExtendedRequest extendedRequest)
1919 throws LDAPException
1920 {
1921 Validator.ensureNotNull(extendedRequest);
1922
1923 final ArrayList<Control> requestControlList =
1924 new ArrayList<Control>(extendedRequest.getControlList());
1925 requestControlList.add(new Control(
1926 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false));
1927
1928
1929 final LDAPMessage responseMessage =
1930 inMemoryHandler.processExtendedRequest(1,
1931 new ExtendedRequestProtocolOp(extendedRequest.getOID(),
1932 extendedRequest.getValue()),
1933 requestControlList);
1934
1935 final ExtendedResponseProtocolOp extendedResponse =
1936 responseMessage.getExtendedResponseProtocolOp();
1937
1938 final ResultCode rc = ResultCode.valueOf(extendedResponse.getResultCode());
1939
1940 final String[] referralURLs;
1941 final List<String> referralURLList = extendedResponse.getReferralURLs();
1942 if ((referralURLList == null) || referralURLList.isEmpty())
1943 {
1944 referralURLs = StaticUtils.NO_STRINGS;
1945 }
1946 else
1947 {
1948 referralURLs = new String[referralURLList.size()];
1949 referralURLList.toArray(referralURLs);
1950 }
1951
1952 final Control[] responseControls;
1953 final List<Control> controlList = responseMessage.getControls();
1954 if ((controlList == null) || controlList.isEmpty())
1955 {
1956 responseControls = StaticUtils.NO_CONTROLS;
1957 }
1958 else
1959 {
1960 responseControls = new Control[controlList.size()];
1961 controlList.toArray(responseControls);
1962 }
1963
1964 final ExtendedResult extendedResult = new ExtendedResult(
1965 responseMessage.getMessageID(), rc,
1966 extendedResponse.getDiagnosticMessage(),
1967 extendedResponse.getMatchedDN(), referralURLs,
1968 extendedResponse.getResponseOID(),
1969 extendedResponse.getResponseValue(), responseControls);
1970
1971 if ((extendedResult.getOID() == null) &&
1972 (extendedResult.getValue() == null))
1973 {
1974 switch (rc.intValue())
1975 {
1976 case ResultCode.OPERATIONS_ERROR_INT_VALUE:
1977 case ResultCode.PROTOCOL_ERROR_INT_VALUE:
1978 case ResultCode.BUSY_INT_VALUE:
1979 case ResultCode.UNAVAILABLE_INT_VALUE:
1980 case ResultCode.OTHER_INT_VALUE:
1981 case ResultCode.SERVER_DOWN_INT_VALUE:
1982 case ResultCode.LOCAL_ERROR_INT_VALUE:
1983 case ResultCode.ENCODING_ERROR_INT_VALUE:
1984 case ResultCode.DECODING_ERROR_INT_VALUE:
1985 case ResultCode.TIMEOUT_INT_VALUE:
1986 case ResultCode.NO_MEMORY_INT_VALUE:
1987 case ResultCode.CONNECT_ERROR_INT_VALUE:
1988 throw new LDAPException(extendedResult);
1989 }
1990 }
1991
1992 return extendedResult;
1993 }
1994
1995
1996
1997 /**
1998 * {@inheritDoc}
1999 * <BR><BR>
2000 * This method may be used regardless of whether the server is listening for
2001 * client connections, and regardless of whether modify operations are allowed
2002 * in the server.
2003 */
2004 public LDAPResult modify(final String dn, final Modification mod)
2005 throws LDAPException
2006 {
2007 return modify(new ModifyRequest(dn, mod));
2008 }
2009
2010
2011
2012 /**
2013 * {@inheritDoc}
2014 * <BR><BR>
2015 * This method may be used regardless of whether the server is listening for
2016 * client connections, and regardless of whether modify operations are allowed
2017 * in the server.
2018 */
2019 public LDAPResult modify(final String dn, final Modification... mods)
2020 throws LDAPException
2021 {
2022 return modify(new ModifyRequest(dn, mods));
2023 }
2024
2025
2026
2027 /**
2028 * {@inheritDoc}
2029 * <BR><BR>
2030 * This method may be used regardless of whether the server is listening for
2031 * client connections, and regardless of whether modify operations are allowed
2032 * in the server.
2033 */
2034 public LDAPResult modify(final String dn, final List<Modification> mods)
2035 throws LDAPException
2036 {
2037 return modify(new ModifyRequest(dn, mods));
2038 }
2039
2040
2041
2042 /**
2043 * {@inheritDoc}
2044 * <BR><BR>
2045 * This method may be used regardless of whether the server is listening for
2046 * client connections, and regardless of whether modify operations are allowed
2047 * in the server.
2048 */
2049 public LDAPResult modify(final String... ldifModificationLines)
2050 throws LDIFException, LDAPException
2051 {
2052 return modify(new ModifyRequest(ldifModificationLines));
2053 }
2054
2055
2056
2057 /**
2058 * {@inheritDoc}
2059 * <BR><BR>
2060 * This method may be used regardless of whether the server is listening for
2061 * client connections, and regardless of whether modify operations are allowed
2062 * in the server.
2063 */
2064 public LDAPResult modify(final ModifyRequest modifyRequest)
2065 throws LDAPException
2066 {
2067 final ArrayList<Control> requestControlList =
2068 new ArrayList<Control>(modifyRequest.getControlList());
2069 requestControlList.add(new Control(
2070 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false));
2071
2072 final LDAPMessage responseMessage = inMemoryHandler.processModifyRequest(1,
2073 new ModifyRequestProtocolOp(modifyRequest.getDN(),
2074 modifyRequest.getModifications()),
2075 requestControlList);
2076
2077 final ModifyResponseProtocolOp modifyResponse =
2078 responseMessage.getModifyResponseProtocolOp();
2079
2080 final LDAPResult ldapResult = new LDAPResult(responseMessage.getMessageID(),
2081 ResultCode.valueOf(modifyResponse.getResultCode()),
2082 modifyResponse.getDiagnosticMessage(), modifyResponse.getMatchedDN(),
2083 modifyResponse.getReferralURLs(), responseMessage.getControls());
2084
2085 switch (modifyResponse.getResultCode())
2086 {
2087 case ResultCode.SUCCESS_INT_VALUE:
2088 case ResultCode.NO_OPERATION_INT_VALUE:
2089 return ldapResult;
2090 default:
2091 throw new LDAPException(ldapResult);
2092 }
2093 }
2094
2095
2096
2097 /**
2098 * {@inheritDoc}
2099 * <BR><BR>
2100 * This method may be used regardless of whether the server is listening for
2101 * client connections, and regardless of whether modify operations are allowed
2102 * in the server.
2103 */
2104 public LDAPResult modify(final ReadOnlyModifyRequest modifyRequest)
2105 throws LDAPException
2106 {
2107 return modify(modifyRequest.duplicate());
2108 }
2109
2110
2111
2112 /**
2113 * {@inheritDoc}
2114 * <BR><BR>
2115 * This method may be used regardless of whether the server is listening for
2116 * client connections, and regardless of whether modify DN operations are
2117 * allowed in the server.
2118 */
2119 public LDAPResult modifyDN(final String dn, final String newRDN,
2120 final boolean deleteOldRDN)
2121 throws LDAPException
2122 {
2123 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN));
2124 }
2125
2126
2127
2128 /**
2129 * {@inheritDoc}
2130 * <BR><BR>
2131 * This method may be used regardless of whether the server is listening for
2132 * client connections, and regardless of whether modify DN operations are
2133 * allowed in the server.
2134 */
2135 public LDAPResult modifyDN(final String dn, final String newRDN,
2136 final boolean deleteOldRDN,
2137 final String newSuperiorDN)
2138 throws LDAPException
2139 {
2140 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN,
2141 newSuperiorDN));
2142 }
2143
2144
2145
2146 /**
2147 * {@inheritDoc}
2148 * <BR><BR>
2149 * This method may be used regardless of whether the server is listening for
2150 * client connections, and regardless of whether modify DN operations are
2151 * allowed in the server.
2152 */
2153 public LDAPResult modifyDN(final ModifyDNRequest modifyDNRequest)
2154 throws LDAPException
2155 {
2156 final ArrayList<Control> requestControlList =
2157 new ArrayList<Control>(modifyDNRequest.getControlList());
2158 requestControlList.add(new Control(
2159 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false));
2160
2161 final LDAPMessage responseMessage = inMemoryHandler.processModifyDNRequest(
2162 1, new ModifyDNRequestProtocolOp(modifyDNRequest.getDN(),
2163 modifyDNRequest.getNewRDN(), modifyDNRequest.deleteOldRDN(),
2164 modifyDNRequest.getNewSuperiorDN()),
2165 requestControlList);
2166
2167 final ModifyDNResponseProtocolOp modifyDNResponse =
2168 responseMessage.getModifyDNResponseProtocolOp();
2169
2170 final LDAPResult ldapResult = new LDAPResult(responseMessage.getMessageID(),
2171 ResultCode.valueOf(modifyDNResponse.getResultCode()),
2172 modifyDNResponse.getDiagnosticMessage(),
2173 modifyDNResponse.getMatchedDN(), modifyDNResponse.getReferralURLs(),
2174 responseMessage.getControls());
2175
2176 switch (modifyDNResponse.getResultCode())
2177 {
2178 case ResultCode.SUCCESS_INT_VALUE:
2179 case ResultCode.NO_OPERATION_INT_VALUE:
2180 return ldapResult;
2181 default:
2182 throw new LDAPException(ldapResult);
2183 }
2184 }
2185
2186
2187
2188 /**
2189 * {@inheritDoc}
2190 * <BR><BR>
2191 * This method may be used regardless of whether the server is listening for
2192 * client connections, and regardless of whether modify DN operations are
2193 * allowed in the server.
2194 */
2195 public LDAPResult modifyDN(final ReadOnlyModifyDNRequest modifyDNRequest)
2196 throws LDAPException
2197 {
2198 return modifyDN(modifyDNRequest.duplicate());
2199 }
2200
2201
2202
2203 /**
2204 * {@inheritDoc}
2205 * <BR><BR>
2206 * This method may be used regardless of whether the server is listening for
2207 * client connections, and regardless of whether search operations are allowed
2208 * in the server.
2209 */
2210 public SearchResult search(final String baseDN, final SearchScope scope,
2211 final String filter, final String... attributes)
2212 throws LDAPSearchException
2213 {
2214 return search(new SearchRequest(baseDN, scope, parseFilter(filter),
2215 attributes));
2216 }
2217
2218
2219
2220 /**
2221 * {@inheritDoc}
2222 * <BR><BR>
2223 * This method may be used regardless of whether the server is listening for
2224 * client connections, and regardless of whether search operations are allowed
2225 * in the server.
2226 */
2227 public SearchResult search(final String baseDN, final SearchScope scope,
2228 final Filter filter, final String... attributes)
2229 throws LDAPSearchException
2230 {
2231 return search(new SearchRequest(baseDN, scope, filter, attributes));
2232 }
2233
2234
2235
2236 /**
2237 * {@inheritDoc}
2238 * <BR><BR>
2239 * This method may be used regardless of whether the server is listening for
2240 * client connections, and regardless of whether search operations are allowed
2241 * in the server.
2242 */
2243 public SearchResult search(final SearchResultListener searchResultListener,
2244 final String baseDN, final SearchScope scope,
2245 final String filter, final String... attributes)
2246 throws LDAPSearchException
2247 {
2248 return search(new SearchRequest(searchResultListener, baseDN, scope,
2249 parseFilter(filter), attributes));
2250 }
2251
2252
2253
2254 /**
2255 * {@inheritDoc}
2256 * <BR><BR>
2257 * This method may be used regardless of whether the server is listening for
2258 * client connections, and regardless of whether search operations are allowed
2259 * in the server.
2260 */
2261 public SearchResult search(final SearchResultListener searchResultListener,
2262 final String baseDN, final SearchScope scope,
2263 final Filter filter, final String... attributes)
2264 throws LDAPSearchException
2265 {
2266 return search(new SearchRequest(searchResultListener, baseDN, scope,
2267 filter, attributes));
2268 }
2269
2270
2271
2272 /**
2273 * {@inheritDoc}
2274 * <BR><BR>
2275 * This method may be used regardless of whether the server is listening for
2276 * client connections, and regardless of whether search operations are allowed
2277 * in the server.
2278 */
2279 public SearchResult search(final String baseDN, final SearchScope scope,
2280 final DereferencePolicy derefPolicy,
2281 final int sizeLimit, final int timeLimit,
2282 final boolean typesOnly, final String filter,
2283 final String... attributes)
2284 throws LDAPSearchException
2285 {
2286 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit,
2287 timeLimit, typesOnly, parseFilter(filter), attributes));
2288 }
2289
2290
2291
2292 /**
2293 * {@inheritDoc}
2294 * <BR><BR>
2295 * This method may be used regardless of whether the server is listening for
2296 * client connections, and regardless of whether search operations are allowed
2297 * in the server.
2298 */
2299 public SearchResult search(final String baseDN, final SearchScope scope,
2300 final DereferencePolicy derefPolicy,
2301 final int sizeLimit, final int timeLimit,
2302 final boolean typesOnly, final Filter filter,
2303 final String... attributes)
2304 throws LDAPSearchException
2305 {
2306 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit,
2307 timeLimit, typesOnly, filter, attributes));
2308 }
2309
2310
2311
2312 /**
2313 * {@inheritDoc}
2314 * <BR><BR>
2315 * This method may be used regardless of whether the server is listening for
2316 * client connections, and regardless of whether search operations are allowed
2317 * in the server.
2318 */
2319 public SearchResult search(final SearchResultListener searchResultListener,
2320 final String baseDN, final SearchScope scope,
2321 final DereferencePolicy derefPolicy,
2322 final int sizeLimit, final int timeLimit,
2323 final boolean typesOnly, final String filter,
2324 final String... attributes)
2325 throws LDAPSearchException
2326 {
2327 return search(new SearchRequest(searchResultListener, baseDN, scope,
2328 derefPolicy, sizeLimit, timeLimit, typesOnly, parseFilter(filter),
2329 attributes));
2330 }
2331
2332
2333
2334 /**
2335 * {@inheritDoc}
2336 * <BR><BR>
2337 * This method may be used regardless of whether the server is listening for
2338 * client connections, and regardless of whether search operations are allowed
2339 * in the server.
2340 */
2341 public SearchResult search(final SearchResultListener searchResultListener,
2342 final String baseDN, final SearchScope scope,
2343 final DereferencePolicy derefPolicy,
2344 final int sizeLimit, final int timeLimit,
2345 final boolean typesOnly, final Filter filter,
2346 final String... attributes)
2347 throws LDAPSearchException
2348 {
2349 return search(new SearchRequest(searchResultListener, baseDN, scope,
2350 derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes));
2351 }
2352
2353
2354
2355 /**
2356 * {@inheritDoc}
2357 * <BR><BR>
2358 * This method may be used regardless of whether the server is listening for
2359 * client connections, and regardless of whether search operations are allowed
2360 * in the server.
2361 */
2362 public SearchResult search(final SearchRequest searchRequest)
2363 throws LDAPSearchException
2364 {
2365 final ArrayList<Control> requestControlList =
2366 new ArrayList<Control>(searchRequest.getControlList());
2367 requestControlList.add(new Control(
2368 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false));
2369
2370 final List<SearchResultEntry> entryList =
2371 new ArrayList<SearchResultEntry>(10);
2372 final List<SearchResultReference> referenceList =
2373 new ArrayList<SearchResultReference>(10);
2374
2375 final LDAPMessage responseMessage = inMemoryHandler.processSearchRequest(1,
2376 new SearchRequestProtocolOp(searchRequest.getBaseDN(),
2377 searchRequest.getScope(), searchRequest.getDereferencePolicy(),
2378 searchRequest.getSizeLimit(), searchRequest.getTimeLimitSeconds(),
2379 searchRequest.typesOnly(), searchRequest.getFilter(),
2380 searchRequest.getAttributeList()),
2381 requestControlList, entryList, referenceList);
2382
2383
2384 final List<SearchResultEntry> returnEntryList;
2385 final List<SearchResultReference> returnReferenceList;
2386 final SearchResultListener searchListener =
2387 searchRequest.getSearchResultListener();
2388 if (searchListener == null)
2389 {
2390 returnEntryList = Collections.unmodifiableList(entryList);
2391 returnReferenceList = Collections.unmodifiableList(referenceList);
2392 }
2393 else
2394 {
2395 returnEntryList = null;
2396 returnReferenceList = null;
2397
2398 for (final SearchResultEntry e : entryList)
2399 {
2400 searchListener.searchEntryReturned(e);
2401 }
2402
2403 for (final SearchResultReference r : referenceList)
2404 {
2405 searchListener.searchReferenceReturned(r);
2406 }
2407 }
2408
2409
2410 final SearchResultDoneProtocolOp searchDone =
2411 responseMessage.getSearchResultDoneProtocolOp();
2412
2413 final ResultCode rc = ResultCode.valueOf(searchDone.getResultCode());
2414
2415 final String[] referralURLs;
2416 final List<String> referralURLList = searchDone.getReferralURLs();
2417 if ((referralURLList == null) || referralURLList.isEmpty())
2418 {
2419 referralURLs = StaticUtils.NO_STRINGS;
2420 }
2421 else
2422 {
2423 referralURLs = new String[referralURLList.size()];
2424 referralURLList.toArray(referralURLs);
2425 }
2426
2427 final Control[] responseControls;
2428 final List<Control> controlList = responseMessage.getControls();
2429 if ((controlList == null) || controlList.isEmpty())
2430 {
2431 responseControls = StaticUtils.NO_CONTROLS;
2432 }
2433 else
2434 {
2435 responseControls = new Control[controlList.size()];
2436 controlList.toArray(responseControls);
2437 }
2438
2439 final SearchResult searchResult =new SearchResult(
2440 responseMessage.getMessageID(), rc, searchDone.getDiagnosticMessage(),
2441 searchDone.getMatchedDN(), referralURLs, returnEntryList,
2442 returnReferenceList, entryList.size(), referenceList.size(),
2443 responseControls);
2444
2445 if (rc == ResultCode.SUCCESS)
2446 {
2447 return searchResult;
2448 }
2449 else
2450 {
2451 throw new LDAPSearchException(searchResult);
2452 }
2453 }
2454
2455
2456
2457 /**
2458 * {@inheritDoc}
2459 * <BR><BR>
2460 * This method may be used regardless of whether the server is listening for
2461 * client connections, and regardless of whether search operations are allowed
2462 * in the server.
2463 */
2464 public SearchResult search(final ReadOnlySearchRequest searchRequest)
2465 throws LDAPSearchException
2466 {
2467 return search(searchRequest.duplicate());
2468 }
2469
2470
2471
2472 /**
2473 * {@inheritDoc}
2474 * <BR><BR>
2475 * This method may be used regardless of whether the server is listening for
2476 * client connections, and regardless of whether search operations are allowed
2477 * in the server.
2478 */
2479 public SearchResultEntry searchForEntry(final String baseDN,
2480 final SearchScope scope,
2481 final String filter,
2482 final String... attributes)
2483 throws LDAPSearchException
2484 {
2485 return searchForEntry(new SearchRequest(baseDN, scope, parseFilter(filter),
2486 attributes));
2487 }
2488
2489
2490
2491 /**
2492 * {@inheritDoc}
2493 * <BR><BR>
2494 * This method may be used regardless of whether the server is listening for
2495 * client connections, and regardless of whether search operations are allowed
2496 * in the server.
2497 */
2498 public SearchResultEntry searchForEntry(final String baseDN,
2499 final SearchScope scope,
2500 final Filter filter,
2501 final String... attributes)
2502 throws LDAPSearchException
2503 {
2504 return searchForEntry(new SearchRequest(baseDN, scope, filter, attributes));
2505 }
2506
2507
2508
2509 /**
2510 * {@inheritDoc}
2511 * <BR><BR>
2512 * This method may be used regardless of whether the server is listening for
2513 * client connections, and regardless of whether search operations are allowed
2514 * in the server.
2515 */
2516 public SearchResultEntry searchForEntry(final String baseDN,
2517 final SearchScope scope,
2518 final DereferencePolicy derefPolicy,
2519 final int timeLimit,
2520 final boolean typesOnly,
2521 final String filter,
2522 final String... attributes)
2523 throws LDAPSearchException
2524 {
2525 return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1,
2526 timeLimit, typesOnly, parseFilter(filter), attributes));
2527 }
2528
2529
2530
2531 /**
2532 * {@inheritDoc}
2533 * <BR><BR>
2534 * This method may be used regardless of whether the server is listening for
2535 * client connections, and regardless of whether search operations are allowed
2536 * in the server.
2537 */
2538 public SearchResultEntry searchForEntry(final String baseDN,
2539 final SearchScope scope,
2540 final DereferencePolicy derefPolicy,
2541 final int timeLimit,
2542 final boolean typesOnly,
2543 final Filter filter,
2544 final String... attributes)
2545 throws LDAPSearchException
2546 {
2547 return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1,
2548 timeLimit, typesOnly, filter, attributes));
2549 }
2550
2551
2552
2553 /**
2554 * {@inheritDoc}
2555 * <BR><BR>
2556 * This method may be used regardless of whether the server is listening for
2557 * client connections, and regardless of whether search operations are allowed
2558 * in the server.
2559 */
2560 public SearchResultEntry searchForEntry(final SearchRequest searchRequest)
2561 throws LDAPSearchException
2562 {
2563 final ArrayList<Control> requestControlList =
2564 new ArrayList<Control>(searchRequest.getControlList());
2565 requestControlList.add(new Control(
2566 InMemoryRequestHandler.OID_INTERNAL_OPERATION_REQUEST_CONTROL, false));
2567
2568 final SearchRequest r;
2569 if ((searchRequest.getSizeLimit() == 1) &&
2570 (searchRequest.getSearchResultListener() == null))
2571 {
2572 r = searchRequest;
2573 }
2574 else
2575 {
2576 r = new SearchRequest(searchRequest.getBaseDN(), searchRequest.getScope(),
2577 searchRequest.getDereferencePolicy(), 1,
2578 searchRequest.getTimeLimitSeconds(), searchRequest.typesOnly(),
2579 searchRequest.getFilter(), searchRequest.getAttributes());
2580
2581 r.setFollowReferrals(InternalSDKHelper.followReferralsInternal(r));
2582 r.setResponseTimeoutMillis(searchRequest.getResponseTimeoutMillis(null));
2583 r.setControls(requestControlList);
2584 }
2585
2586 final SearchResult result;
2587 try
2588 {
2589 result = search(r);
2590 }
2591 catch (final LDAPSearchException lse)
2592 {
2593 Debug.debugException(lse);
2594
2595 if (lse.getResultCode() == ResultCode.NO_SUCH_OBJECT)
2596 {
2597 return null;
2598 }
2599
2600 throw lse;
2601 }
2602
2603 if (result.getEntryCount() == 0)
2604 {
2605 return null;
2606 }
2607 else
2608 {
2609 return result.getSearchEntries().get(0);
2610 }
2611 }
2612
2613
2614
2615 /**
2616 * {@inheritDoc}
2617 * <BR><BR>
2618 * This method may be used regardless of whether the server is listening for
2619 * client connections, and regardless of whether search operations are allowed
2620 * in the server.
2621 */
2622 public SearchResultEntry searchForEntry(
2623 final ReadOnlySearchRequest searchRequest)
2624 throws LDAPSearchException
2625 {
2626 return searchForEntry(searchRequest.duplicate());
2627 }
2628
2629
2630
2631 /**
2632 * Parses the provided string as a search filter.
2633 *
2634 * @param s The string to be parsed.
2635 *
2636 * @return The parsed filter.
2637 *
2638 * @throws LDAPSearchException If the provided string could not be parsed as
2639 * a valid search filter.
2640 */
2641 private static Filter parseFilter(final String s)
2642 throws LDAPSearchException
2643 {
2644 try
2645 {
2646 return Filter.create(s);
2647 }
2648 catch (final LDAPException le)
2649 {
2650 throw new LDAPSearchException(le);
2651 }
2652 }
2653
2654
2655
2656 /**
2657 * Indicates whether the specified entry exists in the server.
2658 * <BR><BR>
2659 * This method may be used regardless of whether the server is listening for
2660 * client connections.
2661 *
2662 * @param dn The DN of the entry for which to make the determination.
2663 *
2664 * @return {@code true} if the entry exists, or {@code false} if not.
2665 *
2666 * @throws LDAPException If a problem is encountered while trying to
2667 * communicate with the directory server.
2668 */
2669 public boolean entryExists(final String dn)
2670 throws LDAPException
2671 {
2672 return inMemoryHandler.entryExists(dn);
2673 }
2674
2675
2676
2677 /**
2678 * Indicates whether the specified entry exists in the server and matches the
2679 * given filter.
2680 * <BR><BR>
2681 * This method may be used regardless of whether the server is listening for
2682 * client connections.
2683 *
2684 * @param dn The DN of the entry for which to make the determination.
2685 * @param filter The filter the entry is expected to match.
2686 *
2687 * @return {@code true} if the entry exists and matches the specified filter,
2688 * or {@code false} if not.
2689 *
2690 * @throws LDAPException If a problem is encountered while trying to
2691 * communicate with the directory server.
2692 */
2693 public boolean entryExists(final String dn, final String filter)
2694 throws LDAPException
2695 {
2696 return inMemoryHandler.entryExists(dn, filter);
2697 }
2698
2699
2700
2701 /**
2702 * Indicates whether the specified entry exists in the server. This will
2703 * return {@code true} only if the target entry exists and contains all values
2704 * for all attributes of the provided entry. The entry will be allowed to
2705 * have attribute values not included in the provided entry.
2706 * <BR><BR>
2707 * This method may be used regardless of whether the server is listening for
2708 * client connections.
2709 *
2710 * @param entry The entry to compare against the directory server.
2711 *
2712 * @return {@code true} if the entry exists in the server and is a superset
2713 * of the provided entry, or {@code false} if not.
2714 *
2715 * @throws LDAPException If a problem is encountered while trying to
2716 * communicate with the directory server.
2717 */
2718 public boolean entryExists(final Entry entry)
2719 throws LDAPException
2720 {
2721 return inMemoryHandler.entryExists(entry);
2722 }
2723
2724
2725
2726 /**
2727 * Ensures that an entry with the provided DN exists in the directory.
2728 * <BR><BR>
2729 * This method may be used regardless of whether the server is listening for
2730 * client connections.
2731 *
2732 * @param dn The DN of the entry for which to make the determination.
2733 *
2734 * @throws LDAPException If a problem is encountered while trying to
2735 * communicate with the directory server.
2736 *
2737 * @throws AssertionError If the target entry does not exist.
2738 */
2739 public void assertEntryExists(final String dn)
2740 throws LDAPException, AssertionError
2741 {
2742 inMemoryHandler.assertEntryExists(dn);
2743 }
2744
2745
2746
2747 /**
2748 * Ensures that an entry with the provided DN exists in the directory.
2749 * <BR><BR>
2750 * This method may be used regardless of whether the server is listening for
2751 * client connections.
2752 *
2753 * @param dn The DN of the entry for which to make the determination.
2754 * @param filter A filter that the target entry must match.
2755 *
2756 * @throws LDAPException If a problem is encountered while trying to
2757 * communicate with the directory server.
2758 *
2759 * @throws AssertionError If the target entry does not exist or does not
2760 * match the provided filter.
2761 */
2762 public void assertEntryExists(final String dn, final String filter)
2763 throws LDAPException, AssertionError
2764 {
2765 inMemoryHandler.assertEntryExists(dn, filter);
2766 }
2767
2768
2769
2770 /**
2771 * Ensures that an entry exists in the directory with the same DN and all
2772 * attribute values contained in the provided entry. The server entry may
2773 * contain additional attributes and/or attribute values not included in the
2774 * provided entry.
2775 * <BR><BR>
2776 * This method may be used regardless of whether the server is listening for
2777 * client connections.
2778 *
2779 * @param entry The entry expected to be present in the directory server.
2780 *
2781 * @throws LDAPException If a problem is encountered while trying to
2782 * communicate with the directory server.
2783 *
2784 * @throws AssertionError If the target entry does not exist or does not
2785 * match the provided filter.
2786 */
2787 public void assertEntryExists(final Entry entry)
2788 throws LDAPException, AssertionError
2789 {
2790 inMemoryHandler.assertEntryExists(entry);
2791 }
2792
2793
2794
2795 /**
2796 * Retrieves a list containing the DNs of the entries which are missing from
2797 * the directory server.
2798 * <BR><BR>
2799 * This method may be used regardless of whether the server is listening for
2800 * client connections.
2801 *
2802 * @param dns The DNs of the entries to try to find in the server.
2803 *
2804 * @return A list containing all of the provided DNs that were not found in
2805 * the server, or an empty list if all entries were found.
2806 *
2807 * @throws LDAPException If a problem is encountered while trying to
2808 * communicate with the directory server.
2809 */
2810 public List<String> getMissingEntryDNs(final String... dns)
2811 throws LDAPException
2812 {
2813 return inMemoryHandler.getMissingEntryDNs(StaticUtils.toList(dns));
2814 }
2815
2816
2817
2818 /**
2819 * Retrieves a list containing the DNs of the entries which are missing from
2820 * the directory server.
2821 * <BR><BR>
2822 * This method may be used regardless of whether the server is listening for
2823 * client connections.
2824 *
2825 * @param dns The DNs of the entries to try to find in the server.
2826 *
2827 * @return A list containing all of the provided DNs that were not found in
2828 * the server, or an empty list if all entries were found.
2829 *
2830 * @throws LDAPException If a problem is encountered while trying to
2831 * communicate with the directory server.
2832 */
2833 public List<String> getMissingEntryDNs(final Collection<String> dns)
2834 throws LDAPException
2835 {
2836 return inMemoryHandler.getMissingEntryDNs(dns);
2837 }
2838
2839
2840
2841 /**
2842 * Ensures that all of the entries with the provided DNs exist in the
2843 * directory.
2844 * <BR><BR>
2845 * This method may be used regardless of whether the server is listening for
2846 * client connections.
2847 *
2848 * @param dns The DNs of the entries for which to make the determination.
2849 *
2850 * @throws LDAPException If a problem is encountered while trying to
2851 * communicate with the directory server.
2852 *
2853 * @throws AssertionError If any of the target entries does not exist.
2854 */
2855 public void assertEntriesExist(final String... dns)
2856 throws LDAPException, AssertionError
2857 {
2858 inMemoryHandler.assertEntriesExist(StaticUtils.toList(dns));
2859 }
2860
2861
2862
2863 /**
2864 * Ensures that all of the entries with the provided DNs exist in the
2865 * directory.
2866 * <BR><BR>
2867 * This method may be used regardless of whether the server is listening for
2868 * client connections.
2869 *
2870 * @param dns The DNs of the entries for which to make the determination.
2871 *
2872 * @throws LDAPException If a problem is encountered while trying to
2873 * communicate with the directory server.
2874 *
2875 * @throws AssertionError If any of the target entries does not exist.
2876 */
2877 public void assertEntriesExist(final Collection<String> dns)
2878 throws LDAPException, AssertionError
2879 {
2880 inMemoryHandler.assertEntriesExist(dns);
2881 }
2882
2883
2884
2885 /**
2886 * Retrieves a list containing all of the named attributes which do not exist
2887 * in the target entry.
2888 * <BR><BR>
2889 * This method may be used regardless of whether the server is listening for
2890 * client connections.
2891 *
2892 * @param dn The DN of the entry to examine.
2893 * @param attributeNames The names of the attributes expected to be present
2894 * in the target entry.
2895 *
2896 * @return A list containing the names of the attributes which were not
2897 * present in the target entry, an empty list if all specified
2898 * attributes were found in the entry, or {@code null} if the target
2899 * entry does not exist.
2900 *
2901 * @throws LDAPException If a problem is encountered while trying to
2902 * communicate with the directory server.
2903 */
2904 public List<String> getMissingAttributeNames(final String dn,
2905 final String... attributeNames)
2906 throws LDAPException
2907 {
2908 return inMemoryHandler.getMissingAttributeNames(dn,
2909 StaticUtils.toList(attributeNames));
2910 }
2911
2912
2913
2914 /**
2915 * Retrieves a list containing all of the named attributes which do not exist
2916 * in the target entry.
2917 * <BR><BR>
2918 * This method may be used regardless of whether the server is listening for
2919 * client connections.
2920 *
2921 * @param dn The DN of the entry to examine.
2922 * @param attributeNames The names of the attributes expected to be present
2923 * in the target entry.
2924 *
2925 * @return A list containing the names of the attributes which were not
2926 * present in the target entry, an empty list if all specified
2927 * attributes were found in the entry, or {@code null} if the target
2928 * entry does not exist.
2929 *
2930 * @throws LDAPException If a problem is encountered while trying to
2931 * communicate with the directory server.
2932 */
2933 public List<String> getMissingAttributeNames(final String dn,
2934 final Collection<String> attributeNames)
2935 throws LDAPException
2936 {
2937 return inMemoryHandler.getMissingAttributeNames(dn, attributeNames);
2938 }
2939
2940
2941
2942 /**
2943 * Ensures that the specified entry exists in the directory with all of the
2944 * specified attributes.
2945 * <BR><BR>
2946 * This method may be used regardless of whether the server is listening for
2947 * client connections.
2948 *
2949 * @param dn The DN of the entry to examine.
2950 * @param attributeNames The names of the attributes that are expected to be
2951 * present in the provided entry.
2952 *
2953 * @throws LDAPException If a problem is encountered while trying to
2954 * communicate with the directory server.
2955 *
2956 * @throws AssertionError If the target entry does not exist or does not
2957 * contain all of the specified attributes.
2958 */
2959 public void assertAttributeExists(final String dn,
2960 final String... attributeNames)
2961 throws LDAPException, AssertionError
2962 {
2963 inMemoryHandler.assertAttributeExists(dn,
2964 StaticUtils.toList(attributeNames));
2965 }
2966
2967
2968
2969 /**
2970 * Ensures that the specified entry exists in the directory with all of the
2971 * specified attributes.
2972 * <BR><BR>
2973 * This method may be used regardless of whether the server is listening for
2974 * client connections.
2975 *
2976 * @param dn The DN of the entry to examine.
2977 * @param attributeNames The names of the attributes that are expected to be
2978 * present in the provided entry.
2979 *
2980 * @throws LDAPException If a problem is encountered while trying to
2981 * communicate with the directory server.
2982 *
2983 * @throws AssertionError If the target entry does not exist or does not
2984 * contain all of the specified attributes.
2985 */
2986 public void assertAttributeExists(final String dn,
2987 final Collection<String> attributeNames)
2988 throws LDAPException, AssertionError
2989 {
2990 inMemoryHandler.assertAttributeExists(dn, attributeNames);
2991 }
2992
2993
2994
2995 /**
2996 * Retrieves a list of all provided attribute values which are missing from
2997 * the specified entry.
2998 * <BR><BR>
2999 * This method may be used regardless of whether the server is listening for
3000 * client connections.
3001 *
3002 * @param dn The DN of the entry to examine.
3003 * @param attributeName The attribute expected to be present in the target
3004 * entry with the given values.
3005 * @param attributeValues The values expected to be present in the target
3006 * entry.
3007 *
3008 * @return A list containing all of the provided values which were not found
3009 * in the entry, an empty list if all provided attribute values were
3010 * found, or {@code null} if the target entry does not exist.
3011 *
3012 * @throws LDAPException If a problem is encountered while trying to
3013 * communicate with the directory server.
3014 */
3015 public List<String> getMissingAttributeValues(final String dn,
3016 final String attributeName,
3017 final String... attributeValues)
3018 throws LDAPException
3019 {
3020 return inMemoryHandler.getMissingAttributeValues(dn, attributeName,
3021 StaticUtils.toList(attributeValues));
3022 }
3023
3024
3025
3026 /**
3027 * Retrieves a list of all provided attribute values which are missing from
3028 * the specified entry. The target attribute may or may not contain
3029 * additional values.
3030 * <BR><BR>
3031 * This method may be used regardless of whether the server is listening for
3032 * client connections.
3033 *
3034 * @param dn The DN of the entry to examine.
3035 * @param attributeName The attribute expected to be present in the target
3036 * entry with the given values.
3037 * @param attributeValues The values expected to be present in the target
3038 * entry.
3039 *
3040 * @return A list containing all of the provided values which were not found
3041 * in the entry, an empty list if all provided attribute values were
3042 * found, or {@code null} if the target entry does not exist.
3043 *
3044 * @throws LDAPException If a problem is encountered while trying to
3045 * communicate with the directory server.
3046 */
3047 public List<String> getMissingAttributeValues(final String dn,
3048 final String attributeName,
3049 final Collection<String> attributeValues)
3050 throws LDAPException
3051 {
3052 return inMemoryHandler.getMissingAttributeValues(dn, attributeName,
3053 attributeValues);
3054 }
3055
3056
3057
3058 /**
3059 * Ensures that the specified entry exists in the directory with all of the
3060 * specified values for the given attribute. The attribute may or may not
3061 * contain additional values.
3062 * <BR><BR>
3063 * This method may be used regardless of whether the server is listening for
3064 * client connections.
3065 *
3066 * @param dn The DN of the entry to examine.
3067 * @param attributeName The name of the attribute to examine.
3068 * @param attributeValues The set of values which must exist for the given
3069 * attribute.
3070 *
3071 * @throws LDAPException If a problem is encountered while trying to
3072 * communicate with the directory server.
3073 *
3074 * @throws AssertionError If the target entry does not exist, does not
3075 * contain the specified attribute, or that attribute
3076 * does not have all of the specified values.
3077 */
3078 public void assertValueExists(final String dn, final String attributeName,
3079 final String... attributeValues)
3080 throws LDAPException, AssertionError
3081 {
3082 inMemoryHandler.assertValueExists(dn, attributeName,
3083 StaticUtils.toList(attributeValues));
3084 }
3085
3086
3087
3088 /**
3089 * Ensures that the specified entry exists in the directory with all of the
3090 * specified values for the given attribute. The attribute may or may not
3091 * contain additional values.
3092 * <BR><BR>
3093 * This method may be used regardless of whether the server is listening for
3094 * client connections.
3095 *
3096 * @param dn The DN of the entry to examine.
3097 * @param attributeName The name of the attribute to examine.
3098 * @param attributeValues The set of values which must exist for the given
3099 * attribute.
3100 *
3101 * @throws LDAPException If a problem is encountered while trying to
3102 * communicate with the directory server.
3103 *
3104 * @throws AssertionError If the target entry does not exist, does not
3105 * contain the specified attribute, or that attribute
3106 * does not have all of the specified values.
3107 */
3108 public void assertValueExists(final String dn, final String attributeName,
3109 final Collection<String> attributeValues)
3110 throws LDAPException, AssertionError
3111 {
3112 inMemoryHandler.assertValueExists(dn, attributeName, attributeValues);
3113 }
3114
3115
3116
3117 /**
3118 * Ensures that the specified entry does not exist in the directory.
3119 * <BR><BR>
3120 * This method may be used regardless of whether the server is listening for
3121 * client connections.
3122 *
3123 * @param dn The DN of the entry expected to be missing.
3124 *
3125 * @throws LDAPException If a problem is encountered while trying to
3126 * communicate with the directory server.
3127 *
3128 * @throws AssertionError If the target entry is found in the server.
3129 */
3130 public void assertEntryMissing(final String dn)
3131 throws LDAPException, AssertionError
3132 {
3133 inMemoryHandler.assertEntryMissing(dn);
3134 }
3135
3136
3137
3138 /**
3139 * Ensures that the specified entry exists in the directory but does not
3140 * contain any of the specified attributes.
3141 * <BR><BR>
3142 * This method may be used regardless of whether the server is listening for
3143 * client connections.
3144 *
3145 * @param dn The DN of the entry expected to be present.
3146 * @param attributeNames The names of the attributes expected to be missing
3147 * from the entry.
3148 *
3149 * @throws LDAPException If a problem is encountered while trying to
3150 * communicate with the directory server.
3151 *
3152 * @throws AssertionError If the target entry is missing from the server, or
3153 * if it contains any of the target attributes.
3154 */
3155 public void assertAttributeMissing(final String dn,
3156 final String... attributeNames)
3157 throws LDAPException, AssertionError
3158 {
3159 inMemoryHandler.assertAttributeMissing(dn,
3160 StaticUtils.toList(attributeNames));
3161 }
3162
3163
3164
3165 /**
3166 * Ensures that the specified entry exists in the directory but does not
3167 * contain any of the specified attributes.
3168 * <BR><BR>
3169 * This method may be used regardless of whether the server is listening for
3170 * client connections.
3171 *
3172 * @param dn The DN of the entry expected to be present.
3173 * @param attributeNames The names of the attributes expected to be missing
3174 * from the entry.
3175 *
3176 * @throws LDAPException If a problem is encountered while trying to
3177 * communicate with the directory server.
3178 *
3179 * @throws AssertionError If the target entry is missing from the server, or
3180 * if it contains any of the target attributes.
3181 */
3182 public void assertAttributeMissing(final String dn,
3183 final Collection<String> attributeNames)
3184 throws LDAPException, AssertionError
3185 {
3186 inMemoryHandler.assertAttributeMissing(dn, attributeNames);
3187 }
3188
3189
3190
3191 /**
3192 * Ensures that the specified entry exists in the directory but does not
3193 * contain any of the specified attribute values.
3194 * <BR><BR>
3195 * This method may be used regardless of whether the server is listening for
3196 * client connections.
3197 *
3198 * @param dn The DN of the entry expected to be present.
3199 * @param attributeName The name of the attribute to examine.
3200 * @param attributeValues The values expected to be missing from the target
3201 * entry.
3202 *
3203 * @throws LDAPException If a problem is encountered while trying to
3204 * communicate with the directory server.
3205 *
3206 * @throws AssertionError If the target entry is missing from the server, or
3207 * if it contains any of the target attribute values.
3208 */
3209 public void assertValueMissing(final String dn, final String attributeName,
3210 final String... attributeValues)
3211 throws LDAPException, AssertionError
3212 {
3213 inMemoryHandler.assertValueMissing(dn, attributeName,
3214 StaticUtils.toList(attributeValues));
3215 }
3216
3217
3218
3219 /**
3220 * Ensures that the specified entry exists in the directory but does not
3221 * contain any of the specified attribute values.
3222 * <BR><BR>
3223 * This method may be used regardless of whether the server is listening for
3224 * client connections.
3225 *
3226 * @param dn The DN of the entry expected to be present.
3227 * @param attributeName The name of the attribute to examine.
3228 * @param attributeValues The values expected to be missing from the target
3229 * entry.
3230 *
3231 * @throws LDAPException If a problem is encountered while trying to
3232 * communicate with the directory server.
3233 *
3234 * @throws AssertionError If the target entry is missing from the server, or
3235 * if it contains any of the target attribute values.
3236 */
3237 public void assertValueMissing(final String dn, final String attributeName,
3238 final Collection<String> attributeValues)
3239 throws LDAPException, AssertionError
3240 {
3241 inMemoryHandler.assertValueMissing(dn, attributeName, attributeValues);
3242 }
3243 }