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