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