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