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