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