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