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