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