001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2009 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.protocols.internal; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.OutputStream; 022import java.util.List; 023 024import org.forgerock.i18n.LocalizableMessage; 025import org.forgerock.opendj.io.ASN1; 026import org.forgerock.opendj.io.ASN1Reader; 027import org.forgerock.opendj.ldap.ByteSequenceReader; 028import org.forgerock.opendj.ldap.ByteString; 029import org.forgerock.opendj.ldap.ByteStringBuilder; 030import org.forgerock.opendj.ldap.DN; 031import org.opends.server.core.*; 032import org.opends.server.protocols.ldap.*; 033import org.opends.server.types.*; 034 035import static org.forgerock.opendj.ldap.DecodeException.*; 036import static org.opends.messages.ProtocolMessages.*; 037import static org.opends.server.protocols.internal.InternalClientConnection.*; 038import static org.opends.server.protocols.internal.Requests.*; 039import static org.opends.server.protocols.ldap.LDAPConstants.*; 040import static org.opends.server.util.ServerConstants.*; 041 042/** 043 * This class provides an implementation of a 044 * {@code java.io.OutputStream} that can be used to facilitate 045 * internal communication with the Directory Server. On the backend, 046 * data written to this output stream will be first decoded as an 047 * ASN.1 element and then as an LDAP message. That LDAP message will 048 * be converted to an internal operation which will then be processed 049 * and the result returned to the client via the input stream on the 050 * other side of the associated internal LDAP socket. 051 */ 052@org.opends.server.types.PublicAPI( 053 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 054 mayInstantiate=false, 055 mayExtend=false, 056 mayInvoke=true) 057public final class InternalLDAPOutputStream 058 extends OutputStream 059 implements InternalSearchListener 060{ 061 /** Indicates whether this stream has been closed. */ 062 private boolean closed; 063 064 private final ASN1Reader reader; 065 066 /** The internal LDAP socket with which this output stream is associated. */ 067 private final InternalLDAPSocket socket; 068 069 /** The immediate data being written. */ 070 private ByteSequenceReader byteBuffer; 071 072 /** 073 * The save buffer used to store any unprocessed data waiting 074 * to be read as ASN.1 elements. (Usually due to writing incomplete 075 * ASN.1 elements.) 076 */ 077 private final ByteStringBuilder saveBuffer; 078 079 private final ByteSequenceReader saveBufferReader; 080 081 /** 082 * An adaptor class for reading from a save buffer and the bytes 083 * being written sequentially using the InputStream interface. 084 * 085 * Since the bytes being written are only available duing the write 086 * call, any unused data will be appended to the save buffer before 087 * returning from the write method. This reader will always read the 088 * save buffer first before the actual bytes being written to ensure 089 * bytes are read in the same order as they are written. 090 */ 091 private class CombinedBufferInputStream extends InputStream 092 { 093 /** {@inheritDoc} */ 094 @Override 095 public int available() 096 { 097 // The number of available bytes is the sum of the save buffer 098 // and the last read data in the NIO ByteStringBuilder. 099 return saveBufferReader.remaining() + byteBuffer.remaining(); 100 } 101 102 /** {@inheritDoc} */ 103 @Override 104 public int read() 105 { 106 if(saveBufferReader.remaining() > 0) 107 { 108 // Try saved buffer first 109 return 0xFF & saveBufferReader.readByte(); 110 } 111 if(byteBuffer.remaining() > 0) 112 { 113 // Must still be on the channel buffer 114 return 0xFF & byteBuffer.readByte(); 115 } 116 117 return -1; 118 } 119 120 /** {@inheritDoc} */ 121 @Override 122 public int read(byte[] bytes) 123 { 124 return read(bytes, 0, bytes.length); 125 } 126 127 /** {@inheritDoc} */ 128 @Override 129 public int read(byte[] value, int off, int length) 130 { 131 int bytesCopied=0; 132 int len; 133 if(saveBufferReader.remaining() > 0) 134 { 135 // Copy out of the last saved buffer first 136 len = Math.min(saveBufferReader.remaining(), length); 137 saveBufferReader.readBytes(value, off, len); 138 bytesCopied += len; 139 } 140 if(bytesCopied < length && byteBuffer.remaining() > 0) 141 { 142 // Copy out of the channel buffer if we haven't got 143 // everything we needed. 144 len = Math.min(byteBuffer.remaining(), length - bytesCopied); 145 byteBuffer.readBytes(value, off + bytesCopied, len); 146 bytesCopied += len; 147 } 148 return bytesCopied; 149 } 150 151 /** {@inheritDoc} */ 152 @Override 153 public long skip(long length) 154 { 155 int bytesSkipped=0; 156 int len; 157 if(saveBufferReader.remaining() > 0) 158 { 159 // Skip in the last saved buffer first 160 len = Math.min(saveBufferReader.remaining(), (int)length); 161 saveBufferReader.position(saveBufferReader.position() + len); 162 bytesSkipped += len; 163 } 164 if(bytesSkipped < length && byteBuffer.remaining() > 0) 165 { 166 //Skip in the channel buffer if we haven't skipped enough. 167 len = Math.min(byteBuffer.remaining(), 168 (int)length - bytesSkipped); 169 byteBuffer.position(byteBuffer.position() + len); 170 bytesSkipped += len; 171 } 172 return bytesSkipped; 173 } 174 } 175 176 /** 177 * Creates a new instance of an internal LDAP output stream that is 178 * associated with the provided internal LDAP socket. 179 * 180 * @param socket The internal LDAP socket that will be serviced by 181 * this internal LDAP output stream. 182 */ 183 public InternalLDAPOutputStream(InternalLDAPSocket socket) 184 { 185 this.socket = socket; 186 this.closed = false; 187 this.saveBuffer = new ByteStringBuilder(); 188 this.saveBufferReader = saveBuffer.asReader(); 189 190 CombinedBufferInputStream bufferStream = 191 new CombinedBufferInputStream(); 192 this.reader = ASN1.getReader(bufferStream); 193 } 194 195 196 197 /** 198 * Closes this output stream, its associated socket, and the 199 * socket's associated input stream. 200 */ 201 @Override 202 public void close() 203 { 204 socket.close(); 205 } 206 207 208 209 /** 210 * Closes this output stream through an internal mechanism that will 211 * not cause an infinite recursion loop by trying to also close the 212 * output stream. 213 */ 214 @org.opends.server.types.PublicAPI( 215 stability=org.opends.server.types.StabilityLevel.PRIVATE, 216 mayInstantiate=false, 217 mayExtend=false, 218 mayInvoke=false) 219 void closeInternal() 220 { 221 closed = true; 222 } 223 224 225 226 /** 227 * Flushes this output stream and forces any buffered data to be 228 * written out. This will have no effect, since this output 229 * stream implementation does not use buffering. 230 */ 231 @Override 232 public void flush() 233 { 234 // No implementation is required. 235 } 236 237 238 239 /** 240 * Writes the contents of the provided byte array to this output 241 * stream. 242 * 243 * @param b The byte array to be written. 244 * 245 * @throws IOException If the output stream is closed, or if there 246 * is a problem with the data being written. 247 */ 248 @Override 249 public void write(byte[] b) 250 throws IOException 251 { 252 write(b, 0, b.length); 253 } 254 255 256 257 /** 258 * Writes the specified portion of the data in the provided byte 259 * array to this output stream. Any data written will be 260 * accumulated until a complete ASN.1 element is available, at which 261 * point it will be decoded as an LDAP message and converted to an 262 * internal operation that will be processed. 263 * 264 * @param b The byte array containing the data to be read. 265 * @param off The position in the array at which to start reading 266 * data. 267 * @param len The number of bytes to read from the array. 268 * 269 * @throws IOException If the output stream is closed, or if there 270 * is a problem with the data being written. 271 */ 272 @Override 273 public synchronized void write(byte[] b, int off, int len) 274 throws IOException 275 { 276 if (closed) 277 { 278 LocalizableMessage m = ERR_INTERNALOS_CLOSED.get(); 279 throw new IOException(m.toString()); 280 } 281 282 byteBuffer = ByteString.wrap(b, off, len).asReader(); 283 284 try 285 { 286 while(reader.elementAvailable()) 287 { 288 LDAPMessage msg = LDAPReader.readMessage(reader); 289 processMessage(msg); 290 } 291 } 292 catch(Exception e) 293 { 294 throw new IOException(e.getMessage()); 295 } 296 297 // Clear the save buffer if we have read all of it 298 if(saveBufferReader.remaining() == 0) 299 { 300 saveBuffer.clear(); 301 saveBufferReader.rewind(); 302 } 303 304 // Append any unused data in the channel buffer to the save buffer 305 if(byteBuffer.remaining() > 0) 306 { 307 saveBuffer.appendBytes(byteBuffer, byteBuffer.remaining()); 308 } 309 } 310 311 312 313 /** 314 * Writes a single byte of data to this output stream. If the byte 315 * written completes an ASN.1 element that was in progress, then it 316 * will be decoded as an LDAP message and converted to an internal 317 * operation that will be processed. Otherwise, the data will be 318 * accumulated until a complete element can be formed. 319 * 320 * @param b The byte to be written. 321 * 322 * @throws IOException If the output stream is closed, or if there 323 * is a problem with the data being written. 324 */ 325 @Override 326 public synchronized void write(int b) 327 throws IOException 328 { 329 write(new byte[]{(byte)b}, 0, 1); 330 } 331 332 333 334 /** 335 * Processes the provided ASN.1 element by decoding it as an LDAP 336 * message, converting that to an internal operation, and sending 337 * the appropriate response message(s) to the client through the 338 * corresponding internal LDAP input stream. 339 * 340 * @param message The LDAP message to process. 341 * 342 * @throws IOException If a problem occurs while attempting to 343 * decode the provided ASN.1 element as an 344 * LDAP message. 345 */ 346 private void processMessage(LDAPMessage message) 347 throws IOException 348 { 349 switch (message.getProtocolOpType()) 350 { 351 case OP_TYPE_ABANDON_REQUEST: 352 // No action is required. 353 return; 354 355 case OP_TYPE_ADD_REQUEST: 356 processAddOperation(message); 357 break; 358 359 case OP_TYPE_BIND_REQUEST: 360 processBindOperation(message); 361 break; 362 363 case OP_TYPE_COMPARE_REQUEST: 364 processCompareOperation(message); 365 break; 366 367 368 case OP_TYPE_DELETE_REQUEST: 369 processDeleteOperation(message); 370 break; 371 372 373 case OP_TYPE_EXTENDED_REQUEST: 374 processExtendedOperation(message); 375 break; 376 377 378 case OP_TYPE_MODIFY_REQUEST: 379 processModifyOperation(message); 380 break; 381 382 383 case OP_TYPE_MODIFY_DN_REQUEST: 384 processModifyDNOperation(message); 385 break; 386 387 388 case OP_TYPE_SEARCH_REQUEST: 389 processSearchOperation(message); 390 break; 391 392 393 case OP_TYPE_UNBIND_REQUEST: 394 socket.close(); 395 break; 396 397 398 default: 399 LocalizableMessage m = ERR_INTERNALOS_INVALID_REQUEST.get( 400 message.getProtocolElementName()); 401 throw new IOException(m.toString()); 402 } 403 } 404 405 406 407 /** 408 * Processes the content of the provided LDAP message as an add 409 * operation and returns the appropriate result to the client. 410 * 411 * @param message The LDAP message containing the request to 412 * process. 413 * 414 * @throws IOException If a problem occurs while attempting to 415 * process the operation. 416 */ 417 private void processAddOperation(LDAPMessage message) 418 throws IOException 419 { 420 int messageID = message.getMessageID(); 421 AddRequestProtocolOp request = message.getAddRequestProtocolOp(); 422 423 InternalClientConnection conn = socket.getConnection(); 424 AddOperationBasis op = 425 new AddOperationBasis(conn, InternalClientConnection.nextOperationID(), 426 messageID, message.getControls(), 427 request.getDN(), 428 request.getAttributes()); 429 op.run(); 430 431 AddResponseProtocolOp addResponse = 432 new AddResponseProtocolOp(op.getResultCode().intValue(), 433 op.getErrorMessage().toMessage(), 434 op.getMatchedDN(), 435 op.getReferralURLs()); 436 List<Control> responseControls = op.getResponseControls(); 437 438 socket.getInputStream().addLDAPMessage( 439 new LDAPMessage(messageID, addResponse, responseControls)); 440 } 441 442 443 444 /** 445 * Processes the content of the provided LDAP message as a bind 446 * operation and returns the appropriate result to the client. 447 * 448 * @param message The LDAP message containing the request to 449 * process. 450 * 451 * @throws IOException If a problem occurs while attempting to 452 * process the operation. 453 */ 454 private void processBindOperation(LDAPMessage message) 455 throws IOException 456 { 457 int messageID = message.getMessageID(); 458 BindRequestProtocolOp request = 459 message.getBindRequestProtocolOp(); 460 461 if (request.getAuthenticationType() == AuthenticationType.SASL) 462 { 463 LocalizableMessage m = ERR_INTERNALOS_SASL_BIND_NOT_SUPPORTED.get(); 464 BindResponseProtocolOp bindResponse = 465 new BindResponseProtocolOp( 466 LDAPResultCode.UNWILLING_TO_PERFORM, m); 467 socket.getInputStream().addLDAPMessage( 468 new LDAPMessage(messageID, bindResponse)); 469 return; 470 } 471 472 InternalClientConnection conn = socket.getConnection(); 473 BindOperationBasis op = 474 new BindOperationBasis(conn, nextOperationID(), 475 messageID, message.getControls(), 476 String.valueOf(request.getProtocolVersion()), 477 request.getDN(), request.getSimplePassword()); 478 op.run(); 479 480 BindResponseProtocolOp bindResponse = 481 new BindResponseProtocolOp(op.getResultCode().intValue(), 482 op.getErrorMessage().toMessage(), 483 op.getMatchedDN(), 484 op.getReferralURLs()); 485 List<Control> responseControls = op.getResponseControls(); 486 487 if (bindResponse.getResultCode() == LDAPResultCode.SUCCESS) 488 { 489 socket.setConnection(new InternalClientConnection( 490 op.getAuthenticationInfo())); 491 } 492 493 socket.getInputStream().addLDAPMessage( 494 new LDAPMessage(messageID, bindResponse, responseControls)); 495 } 496 497 498 499 /** 500 * Processes the content of the provided LDAP message as a compare 501 * operation and returns the appropriate result to the client. 502 * 503 * @param message The LDAP message containing the request to 504 * process. 505 * 506 * @throws IOException If a problem occurs while attempting to 507 * process the operation. 508 */ 509 private void processCompareOperation(LDAPMessage message) 510 throws IOException 511 { 512 int messageID = message.getMessageID(); 513 CompareRequestProtocolOp request = 514 message.getCompareRequestProtocolOp(); 515 516 InternalClientConnection conn = socket.getConnection(); 517 CompareOperationBasis op = 518 new CompareOperationBasis(conn, nextOperationID(), 519 messageID, message.getControls(), request.getDN(), 520 request.getAttributeType(), 521 request.getAssertionValue()); 522 op.run(); 523 524 CompareResponseProtocolOp compareResponse = 525 new CompareResponseProtocolOp( 526 op.getResultCode().intValue(), 527 op.getErrorMessage().toMessage(), 528 op.getMatchedDN(), 529 op.getReferralURLs()); 530 List<Control> responseControls = op.getResponseControls(); 531 532 socket.getInputStream().addLDAPMessage( 533 new LDAPMessage(messageID, compareResponse, 534 responseControls)); 535 } 536 537 538 539 /** 540 * Processes the content of the provided LDAP message as a delete 541 * operation and returns the appropriate result to the client. 542 * 543 * @param message The LDAP message containing the request to 544 * process. 545 * 546 * @throws IOException If a problem occurs while attempting to 547 * process the operation. 548 */ 549 private void processDeleteOperation(LDAPMessage message) 550 throws IOException 551 { 552 int messageID = message.getMessageID(); 553 DeleteRequestProtocolOp request = 554 message.getDeleteRequestProtocolOp(); 555 556 InternalClientConnection conn = socket.getConnection(); 557 DeleteOperationBasis op = 558 new DeleteOperationBasis(conn, nextOperationID(), 559 messageID, message.getControls(), request.getDN()); 560 op.run(); 561 562 DeleteResponseProtocolOp deleteResponse = 563 new DeleteResponseProtocolOp( 564 op.getResultCode().intValue(), 565 op.getErrorMessage().toMessage(), 566 op.getMatchedDN(), 567 op.getReferralURLs()); 568 List<Control> responseControls = op.getResponseControls(); 569 570 socket.getInputStream().addLDAPMessage( 571 new LDAPMessage(messageID, deleteResponse, 572 responseControls)); 573 } 574 575 576 577 /** 578 * Processes the content of the provided LDAP message as an extended 579 * operation and returns the appropriate result to the client. 580 * 581 * @param message The LDAP message containing the request to 582 * process. 583 * 584 * @throws IOException If a problem occurs while attempting to 585 * process the operation. 586 */ 587 private void processExtendedOperation(LDAPMessage message) 588 throws IOException 589 { 590 int messageID = message.getMessageID(); 591 ExtendedRequestProtocolOp request = 592 message.getExtendedRequestProtocolOp(); 593 if (request.getOID().equals(OID_START_TLS_REQUEST)) 594 { 595 LocalizableMessage m = ERR_INTERNALOS_STARTTLS_NOT_SUPPORTED.get(); 596 ExtendedResponseProtocolOp extendedResponse = 597 new ExtendedResponseProtocolOp( 598 LDAPResultCode.UNWILLING_TO_PERFORM, m); 599 socket.getInputStream().addLDAPMessage( 600 new LDAPMessage(messageID, extendedResponse)); 601 return; 602 } 603 604 InternalClientConnection conn = socket.getConnection(); 605 ExtendedOperationBasis op = 606 new ExtendedOperationBasis(conn, nextOperationID(), 607 messageID, message.getControls(), request.getOID(), 608 request.getValue()); 609 op.run(); 610 611 ExtendedResponseProtocolOp extendedResponse = 612 new ExtendedResponseProtocolOp( 613 op.getResultCode().intValue(), 614 op.getErrorMessage().toMessage(), 615 op.getMatchedDN(), 616 op.getReferralURLs(), op.getResponseOID(), 617 op.getResponseValue()); 618 List<Control> responseControls = op.getResponseControls(); 619 620 socket.getInputStream().addLDAPMessage( 621 new LDAPMessage(messageID, extendedResponse, 622 responseControls)); 623 } 624 625 626 627 /** 628 * Processes the content of the provided LDAP message as a modify 629 * operation and returns the appropriate result to the client. 630 * 631 * @param message The LDAP message containing the request to 632 * process. 633 * 634 * @throws IOException If a problem occurs while attempting to 635 * process the operation. 636 */ 637 private void processModifyOperation(LDAPMessage message) 638 throws IOException 639 { 640 int messageID = message.getMessageID(); 641 ModifyRequestProtocolOp request = 642 message.getModifyRequestProtocolOp(); 643 644 InternalClientConnection conn = socket.getConnection(); 645 ModifyOperationBasis op = 646 new ModifyOperationBasis(conn, nextOperationID(), 647 messageID, message.getControls(), request.getDN(), 648 request.getModifications()); 649 op.run(); 650 651 ModifyResponseProtocolOp modifyResponse = 652 new ModifyResponseProtocolOp( 653 op.getResultCode().intValue(), 654 op.getErrorMessage().toMessage(), 655 op.getMatchedDN(), 656 op.getReferralURLs()); 657 List<Control> responseControls = op.getResponseControls(); 658 659 socket.getInputStream().addLDAPMessage( 660 new LDAPMessage(messageID, modifyResponse, 661 responseControls)); 662 } 663 664 665 666 /** 667 * Processes the content of the provided LDAP message as a modify DN 668 * operation and returns the appropriate result to the client. 669 * 670 * @param message The LDAP message containing the request to 671 * process. 672 * 673 * @throws IOException If a problem occurs while attempting to 674 * process the operation. 675 */ 676 private void processModifyDNOperation(LDAPMessage message) 677 throws IOException 678 { 679 int messageID = message.getMessageID(); 680 ModifyDNRequestProtocolOp request = 681 message.getModifyDNRequestProtocolOp(); 682 683 InternalClientConnection conn = socket.getConnection(); 684 ModifyDNOperationBasis op = 685 new ModifyDNOperationBasis(conn, nextOperationID(), 686 messageID, message.getControls(), request.getEntryDN(), 687 request.getNewRDN(), request.deleteOldRDN(), 688 request.getNewSuperior()); 689 op.run(); 690 691 ModifyDNResponseProtocolOp modifyDNResponse = 692 new ModifyDNResponseProtocolOp( 693 op.getResultCode().intValue(), 694 op.getErrorMessage().toMessage(), 695 op.getMatchedDN(), 696 op.getReferralURLs()); 697 List<Control> responseControls = op.getResponseControls(); 698 699 socket.getInputStream().addLDAPMessage( 700 new LDAPMessage(messageID, modifyDNResponse, 701 responseControls)); 702 } 703 704 705 706 /** 707 * Processes the content of the provided LDAP message as a search 708 * operation and returns the appropriate result to the client. 709 * 710 * @param message The LDAP message containing the request to 711 * process. 712 * 713 * @throws IOException If a problem occurs while attempting to 714 * process the operation. 715 */ 716 private void processSearchOperation(LDAPMessage message) 717 throws IOException 718 { 719 int messageID = message.getMessageID(); 720 SearchRequestProtocolOp request = message.getSearchRequestProtocolOp(); 721 722 InternalClientConnection conn = socket.getConnection(); 723 DN baseDN = null; 724 SearchFilter filter; 725 try 726 { 727 baseDN = DN.valueOf(request.getBaseDN().toString()); 728 filter = request.getFilter().toSearchFilter(); 729 } 730 catch (DirectoryException e) 731 { 732 final String cause = baseDN == null ? "baseDN" : "filter"; 733 throw error(LocalizableMessage.raw("Could not decode " + cause), e); 734 } 735 SearchRequest sr = newSearchRequest(baseDN, request.getScope(), filter) 736 .setDereferenceAliasesPolicy(request.getDereferencePolicy()) 737 .setSizeLimit(request.getSizeLimit()) 738 .setTimeLimit(request.getTimeLimit()) 739 .setTypesOnly(request.getTypesOnly()) 740 .addAttribute(request.getAttributes()) 741 .addControl(message.getControls()); 742 InternalSearchOperation op = new InternalSearchOperation( 743 conn, nextOperationID(), messageID, sr, this); 744 op.run(); 745 746 SearchResultDoneProtocolOp searchDone = 747 new SearchResultDoneProtocolOp( 748 op.getResultCode().intValue(), 749 op.getErrorMessage().toMessage(), 750 op.getMatchedDN(), 751 op.getReferralURLs()); 752 List<Control> responseControls = op.getResponseControls(); 753 754 socket.getInputStream().addLDAPMessage( 755 new LDAPMessage(messageID, searchDone, responseControls)); 756 } 757 758 759 760 /** 761 * Performs any processing necessary for the provided search result 762 * entry. 763 * 764 * @param searchOperation The internal search operation being 765 * processed. 766 * @param searchEntry The matching search result entry to be 767 * processed. 768 */ 769 @Override 770 @org.opends.server.types.PublicAPI( 771 stability=org.opends.server.types.StabilityLevel.PRIVATE, 772 mayInstantiate=false, 773 mayExtend=false, 774 mayInvoke=false) 775 public void handleInternalSearchEntry( 776 InternalSearchOperation searchOperation, 777 SearchResultEntry searchEntry) 778 { 779 List<Control> entryControls = searchEntry.getControls(); 780 781 SearchResultEntryProtocolOp entry = 782 new SearchResultEntryProtocolOp(searchEntry); 783 784 socket.getInputStream().addLDAPMessage( 785 new LDAPMessage(searchOperation.getMessageID(), entry, entryControls)); 786 } 787 788 789 790 /** 791 * Performs any processing necessary for the provided search result reference. 792 * 793 * @param searchOperation The internal search operation being processed. 794 * @param searchReference The search result reference to be processed. 795 */ 796 @Override 797 @org.opends.server.types.PublicAPI( 798 stability=org.opends.server.types.StabilityLevel.PRIVATE, 799 mayInstantiate=false, 800 mayExtend=false, 801 mayInvoke=false) 802 public void handleInternalSearchReference( 803 InternalSearchOperation searchOperation, 804 SearchResultReference searchReference) 805 { 806 List<Control> entryControls = searchReference.getControls(); 807 808 SearchResultReferenceProtocolOp reference = 809 new SearchResultReferenceProtocolOp(searchReference); 810 811 socket.getInputStream().addLDAPMessage( 812 new LDAPMessage(searchOperation.getMessageID(), reference, 813 entryControls)); 814 } 815 816 817 818 /** 819 * Retrieves a string representation of this internal LDAP socket. 820 * 821 * @return A string representation of this internal LDAP socket. 822 */ 823 @Override 824 public String toString() 825 { 826 return getClass().getSimpleName(); 827 } 828}