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