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