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