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