001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.protocols.internal;
028
029
030
031 import java.io.OutputStream;
032 import java.io.IOException;
033 import java.util.ArrayList;
034
035 import org.opends.messages.Message;
036 import org.opends.server.core.*;
037 import org.opends.server.protocols.asn1.ASN1Element;
038 import org.opends.server.protocols.ldap.*;
039 import org.opends.server.types.AuthenticationType;
040 import org.opends.server.types.Control;
041 import org.opends.server.types.SearchResultEntry;
042 import org.opends.server.types.SearchResultReference;
043
044 import static org.opends.messages.ProtocolMessages.*;
045 import static org.opends.server.protocols.ldap.LDAPConstants.*;
046 import static org.opends.server.util.ServerConstants.*;
047
048
049
050 /**
051 * This class provides an implementation of a
052 * {@code java.io.OutputStream} that can be used to facilitate
053 * internal communication with the Directory Server. On the backend,
054 * data written to this output stream will be first decoded as an
055 * ASN.1 element and then as an LDAP message. That LDAP message will
056 * be converted to an internal operation which will then be processed
057 * and the result returned to the client via the input stream on the
058 * other side of the associated internal LDAP socket.
059 */
060 @org.opends.server.types.PublicAPI(
061 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
062 mayInstantiate=false,
063 mayExtend=false,
064 mayInvoke=true)
065 public final class InternalLDAPOutputStream
066 extends OutputStream
067 implements InternalSearchListener
068 {
069 // Indicates whether this stream has been closed.
070 private boolean closed;
071
072 // Indicates whether the type of the ASN.1 element is needed.
073 private boolean needType;
074
075 // The BER type for the ASN.1 element being read.
076 private byte elementType;
077
078 // The data for the ASN.1 element being read.
079 private byte[] elementBytes;
080
081 // The length bytes for the ASN.1 element being read.
082 private byte[] lengthBytes;
083
084 // The offset in the appropriate array at which we should begin
085 // writing data. This could either refer to the length or data
086 // array, depending on the stage of the encoding process.
087 private int arrayOffset;
088
089 // The internal LDAP socket with which this output stream is
090 // associated.
091 private InternalLDAPSocket socket;
092
093
094
095 /**
096 * Creates a new instance of an internal LDAP output stream that is
097 * associated with the provided internal LDAP socket.
098 *
099 * @param socket The internal LDAP socket that will be serviced by
100 * this internal LDAP output stream.
101 */
102 public InternalLDAPOutputStream(InternalLDAPSocket socket)
103 {
104 this.socket = socket;
105
106 closed = false;
107
108 needType = true;
109 elementType = 0x00;
110 elementBytes = null;
111 lengthBytes = null;
112 arrayOffset = 0;
113 }
114
115
116
117 /**
118 * Closes this output stream, its associated socket, and the
119 * socket's associated input stream.
120 */
121 @Override()
122 public void close()
123 {
124 socket.close();
125 }
126
127
128
129 /**
130 * Closes this output stream through an internal mechanism that will
131 * not cause an infinite recursion loop by trying to also close the
132 * output stream.
133 */
134 @org.opends.server.types.PublicAPI(
135 stability=org.opends.server.types.StabilityLevel.PRIVATE,
136 mayInstantiate=false,
137 mayExtend=false,
138 mayInvoke=false)
139 void closeInternal()
140 {
141 closed = true;
142 }
143
144
145
146 /**
147 * Flushes this output stream and forces any buffered data to be
148 * written out. This will have no effect, since this output
149 * stream implementation does not use buffering.
150 */
151 @Override()
152 public void flush()
153 {
154 // No implementation is required.
155 }
156
157
158
159 /**
160 * Writes the contents of the provided byte array to this output
161 * stream.
162 *
163 * @param b The byte array to be written.
164 *
165 * @throws IOException If the output stream is closed, or if there
166 * is a problem with the data being written.
167 */
168 @Override()
169 public void write(byte[] b)
170 throws IOException
171 {
172 write(b, 0, b.length);
173 }
174
175
176
177 /**
178 * Writes the specified portion of the data in the provided byte
179 * array to this output stream. Any data written will be
180 * accumulated until a complete ASN.1 element is available, at which
181 * point it will be decoded as an LDAP message and converted to an
182 * internal operation that will be processed.
183 *
184 * @param b The byte array containing the data to be read.
185 * @param off The position in the array at which to start reading
186 * data.
187 * @param len The number of bytes to read from the array.
188 *
189 * @throws IOException If the output stream is closed, or if there
190 * is a problem with the data being written.
191 */
192 @Override()
193 public synchronized void write(byte[] b, int off, int len)
194 throws IOException
195 {
196 if (closed)
197 {
198 Message m = ERR_INTERNALOS_CLOSED.get();
199 throw new IOException(m.toString());
200 }
201
202 if (len == 0)
203 {
204 return;
205 }
206
207
208 // See if we need to read the BER type.
209 int position = off;
210 int remaining = len;
211 if (needType)
212 {
213 elementType = b[position++];
214 needType = false;
215
216 if (--remaining <= 0)
217 {
218 return;
219 }
220 }
221
222
223 // See if we need to read the first length byte.
224 if ((lengthBytes == null) && (elementBytes == null))
225 {
226 int length = b[position++];
227 if (length == (length & 0x7F))
228 {
229 // It's a single-byte length, so we can create the value
230 // array.
231 elementBytes = new byte[length];
232 }
233 else
234 {
235 // It's a multi-byte length, so we can create the length
236 // array.
237 lengthBytes = new byte[length & 0x7F];
238 }
239
240 arrayOffset = 0;
241 if (--remaining <= 0)
242 {
243 return;
244 }
245 }
246
247
248 // See if we need to continue reading part of a multi-byte length.
249 if (lengthBytes != null)
250 {
251 // See if we have enough to read the full length. If so, then
252 // do it. Otherwise, read what we can and return.
253 int needed = lengthBytes.length - arrayOffset;
254 if (remaining >= needed)
255 {
256 System.arraycopy(b, position, lengthBytes, arrayOffset,
257 needed);
258 position += needed;
259 remaining -= needed;
260
261 int length = 0;
262 for (byte lb : lengthBytes)
263 {
264 length <<= 8;
265 length |= (lb & 0xFF);
266 }
267
268 elementBytes = new byte[length];
269 lengthBytes = null;
270 arrayOffset = 0;
271 if (remaining <= 0)
272 {
273 return;
274 }
275 }
276 else
277 {
278 System.arraycopy(b, position, lengthBytes, arrayOffset,
279 remaining);
280 arrayOffset += remaining;
281 return;
282 }
283 }
284
285
286 // See if we need to read data for the element value.
287 if (elementBytes != null)
288 {
289 // See if we have enough to read the full value. If so, then
290 // do it, create the element, and process it. Otherwise, read
291 // what we can and return.
292 int needed = elementBytes.length - arrayOffset;
293 if (remaining >= needed)
294 {
295 System.arraycopy(b, position, elementBytes, arrayOffset,
296 needed);
297 position += needed;
298 remaining -= needed;
299 processElement(new ASN1Element(elementType, elementBytes));
300
301 needType = true;
302 arrayOffset = 0;
303 lengthBytes = null;
304 elementBytes = null;
305 }
306 else
307 {
308 System.arraycopy(b, position, lengthBytes, arrayOffset,
309 remaining);
310 arrayOffset += remaining;
311 return;
312 }
313 }
314
315
316 // If there is still more data available, then call this method
317 // again to process it.
318 if (remaining > 0)
319 {
320 write(b, position, remaining);
321 }
322 }
323
324
325
326 /**
327 * Writes a single byte of data to this output stream. If the byte
328 * written completes an ASN.1 element that was in progress, then it
329 * will be decoded as an LDAP message and converted to an internal
330 * operation that will be processed. Otherwise, the data will be
331 * accumulated until a complete element can be formed.
332 *
333 * @param b The byte to be written.
334 *
335 * @throws IOException If the output stream is closed, or if there
336 * is a problem with the data being written.
337 */
338 @Override()
339 public synchronized void write(int b)
340 throws IOException
341 {
342 if (closed)
343 {
344 Message m = ERR_INTERNALOS_CLOSED.get();
345 throw new IOException(m.toString());
346 }
347
348 if (needType)
349 {
350 elementType = (byte) (b & 0xFF);
351 needType = false;
352 return;
353 }
354 else if (elementBytes != null)
355 {
356 // The byte should be part of the element value.
357 elementBytes[arrayOffset++] = (byte) (b & 0xFF);
358 if (arrayOffset == elementBytes.length)
359 {
360 // The element has been completed, so process it.
361 processElement(new ASN1Element(elementType, elementBytes));
362 }
363
364 lengthBytes = null;
365 elementBytes = null;
366 arrayOffset = 0;
367 needType = true;
368
369 return;
370 }
371 else if (lengthBytes != null)
372 {
373 // The byte should be part of a multi-byte length.
374 lengthBytes[arrayOffset++] = (byte) (b & 0xFF);
375 if (arrayOffset == lengthBytes.length)
376 {
377 int length = 0;
378 for (int i=0; i < lengthBytes.length; i++)
379 {
380 length <<= 8;
381 length |= (lengthBytes[i] & 0xFF);
382 }
383
384 elementBytes = new byte[length];
385 lengthBytes = null;
386 arrayOffset = 0;
387 }
388
389 return;
390 }
391 else
392 {
393 if ((b & 0x7F) == b)
394 {
395 // It's the complete length.
396 elementBytes = new byte[b];
397 lengthBytes = null;
398 arrayOffset = 0;
399 }
400 else
401 {
402 lengthBytes = new byte[b & 0x7F];
403 elementBytes = null;
404 arrayOffset = 0;
405 }
406
407 return;
408 }
409 }
410
411
412
413 /**
414 * Processes the provided ASN.1 element by decoding it as an LDAP
415 * message, converting that to an internal operation, and sending
416 * the appropriate response message(s) to the client through the
417 * corresponding internal LDAP input stream.
418 *
419 * @param element The ASN.1 element to be processed.
420 *
421 * @throws IOException If a problem occurs while attempting to
422 * decode the provided ASN.1 element as an
423 * LDAP message.
424 */
425 private void processElement(ASN1Element element)
426 throws IOException
427 {
428 LDAPMessage message;
429 try
430 {
431 message = LDAPMessage.decode(element.decodeAsSequence());
432 }
433 catch (Exception e)
434 {
435 throw new IOException(e.getMessage());
436 }
437
438 switch (message.getProtocolOpType())
439 {
440 case OP_TYPE_ABANDON_REQUEST:
441 // No action is required.
442 return;
443
444 case OP_TYPE_ADD_REQUEST:
445 processAddOperation(message);
446 break;
447
448 case OP_TYPE_BIND_REQUEST:
449 processBindOperation(message);
450 break;
451
452 case OP_TYPE_COMPARE_REQUEST:
453 processCompareOperation(message);
454 break;
455
456
457 case OP_TYPE_DELETE_REQUEST:
458 processDeleteOperation(message);
459 break;
460
461
462 case OP_TYPE_EXTENDED_REQUEST:
463 processExtendedOperation(message);
464 break;
465
466
467 case OP_TYPE_MODIFY_REQUEST:
468 processModifyOperation(message);
469 break;
470
471
472 case OP_TYPE_MODIFY_DN_REQUEST:
473 processModifyDNOperation(message);
474 break;
475
476
477 case OP_TYPE_SEARCH_REQUEST:
478 processSearchOperation(message);
479 break;
480
481
482 case OP_TYPE_UNBIND_REQUEST:
483 socket.close();
484 break;
485
486
487 default:
488 Message m = ERR_INTERNALOS_INVALID_REQUEST.get(
489 message.getProtocolElementName());
490 throw new IOException(m.toString());
491 }
492 }
493
494
495
496 /**
497 * Processes the content of the provided LDAP message as an add
498 * operation and returns the appropriate result to the client.
499 *
500 * @param message The LDAP message containing the request to
501 * process.
502 *
503 * @throws IOException If a problem occurs while attempting to
504 * process the operation.
505 */
506 private void processAddOperation(LDAPMessage message)
507 throws IOException
508 {
509 int messageID = message.getMessageID();
510 AddRequestProtocolOp request = message.getAddRequestProtocolOp();
511
512 ArrayList<Control> requestControls = new ArrayList<Control>();
513 if (message.getControls() != null)
514 {
515 for (LDAPControl c : message.getControls())
516 {
517 requestControls.add(c.getControl());
518 }
519 }
520
521 InternalClientConnection conn = socket.getConnection();
522 AddOperationBasis op =
523 new AddOperationBasis(conn, conn.nextOperationID(),
524 messageID, requestControls,
525 request.getDN(),
526 request.getAttributes());
527 op.run();
528
529 AddResponseProtocolOp addResponse =
530 new AddResponseProtocolOp(op.getResultCode().getIntValue(),
531 op.getErrorMessage().toMessage(),
532 op.getMatchedDN(),
533 op.getReferralURLs());
534 ArrayList<LDAPControl> responseControls =
535 new ArrayList<LDAPControl>();
536 for (Control c : op.getResponseControls())
537 {
538 responseControls.add(new LDAPControl(c));
539 }
540
541 socket.getInputStream().addLDAPMessage(
542 new LDAPMessage(messageID, addResponse, responseControls));
543 }
544
545
546
547 /**
548 * Processes the content of the provided LDAP message as a bind
549 * operation and returns the appropriate result to the client.
550 *
551 * @param message The LDAP message containing the request to
552 * process.
553 *
554 * @throws IOException If a problem occurs while attempting to
555 * process the operation.
556 */
557 private void processBindOperation(LDAPMessage message)
558 throws IOException
559 {
560 int messageID = message.getMessageID();
561 BindRequestProtocolOp request =
562 message.getBindRequestProtocolOp();
563
564 if (request.getAuthenticationType() == AuthenticationType.SASL)
565 {
566 Message m = ERR_INTERNALOS_SASL_BIND_NOT_SUPPORTED.get();
567 BindResponseProtocolOp bindResponse =
568 new BindResponseProtocolOp(
569 LDAPResultCode.UNWILLING_TO_PERFORM, m);
570 socket.getInputStream().addLDAPMessage(
571 new LDAPMessage(messageID, bindResponse));
572 return;
573 }
574
575 ArrayList<Control> requestControls = new ArrayList<Control>();
576 if (message.getControls() != null)
577 {
578 for (LDAPControl c : message.getControls())
579 {
580 requestControls.add(c.getControl());
581 }
582 }
583
584 InternalClientConnection conn = socket.getConnection();
585 BindOperationBasis op =
586 new BindOperationBasis(conn, conn.nextOperationID(),
587 messageID, requestControls,
588 String.valueOf(request.getProtocolVersion()),
589 request.getDN(), request.getSimplePassword());
590 op.run();
591
592 BindResponseProtocolOp bindResponse =
593 new BindResponseProtocolOp(op.getResultCode().getIntValue(),
594 op.getErrorMessage().toMessage(),
595 op.getMatchedDN(),
596 op.getReferralURLs());
597 ArrayList<LDAPControl> responseControls =
598 new ArrayList<LDAPControl>();
599 for (Control c : op.getResponseControls())
600 {
601 responseControls.add(new LDAPControl(c));
602 }
603
604 if (bindResponse.getResultCode() == LDAPResultCode.SUCCESS)
605 {
606 socket.setConnection(new InternalClientConnection(
607 op.getAuthenticationInfo()));
608 }
609
610 socket.getInputStream().addLDAPMessage(
611 new LDAPMessage(messageID, bindResponse, responseControls));
612 }
613
614
615
616 /**
617 * Processes the content of the provided LDAP message as a compare
618 * operation and returns the appropriate result to the client.
619 *
620 * @param message The LDAP message containing the request to
621 * process.
622 *
623 * @throws IOException If a problem occurs while attempting to
624 * process the operation.
625 */
626 private void processCompareOperation(LDAPMessage message)
627 throws IOException
628 {
629 int messageID = message.getMessageID();
630 CompareRequestProtocolOp request =
631 message.getCompareRequestProtocolOp();
632
633 ArrayList<Control> requestControls = new ArrayList<Control>();
634 if (message.getControls() != null)
635 {
636 for (LDAPControl c : message.getControls())
637 {
638 requestControls.add(c.getControl());
639 }
640 }
641
642 InternalClientConnection conn = socket.getConnection();
643 CompareOperationBasis op =
644 new CompareOperationBasis(conn, conn.nextOperationID(),
645 messageID, requestControls, request.getDN(),
646 request.getAttributeType(),
647 request.getAssertionValue());
648 op.run();
649
650 CompareResponseProtocolOp compareResponse =
651 new CompareResponseProtocolOp(
652 op.getResultCode().getIntValue(),
653 op.getErrorMessage().toMessage(),
654 op.getMatchedDN(),
655 op.getReferralURLs());
656 ArrayList<LDAPControl> responseControls =
657 new ArrayList<LDAPControl>();
658 for (Control c : op.getResponseControls())
659 {
660 responseControls.add(new LDAPControl(c));
661 }
662
663 socket.getInputStream().addLDAPMessage(
664 new LDAPMessage(messageID, compareResponse,
665 responseControls));
666 }
667
668
669
670 /**
671 * Processes the content of the provided LDAP message as a delete
672 * operation and returns the appropriate result to the client.
673 *
674 * @param message The LDAP message containing the request to
675 * process.
676 *
677 * @throws IOException If a problem occurs while attempting to
678 * process the operation.
679 */
680 private void processDeleteOperation(LDAPMessage message)
681 throws IOException
682 {
683 int messageID = message.getMessageID();
684 DeleteRequestProtocolOp request =
685 message.getDeleteRequestProtocolOp();
686
687 ArrayList<Control> requestControls = new ArrayList<Control>();
688 if (message.getControls() != null)
689 {
690 for (LDAPControl c : message.getControls())
691 {
692 requestControls.add(c.getControl());
693 }
694 }
695
696 InternalClientConnection conn = socket.getConnection();
697 DeleteOperationBasis op =
698 new DeleteOperationBasis(conn, conn.nextOperationID(),
699 messageID, requestControls, request.getDN());
700 op.run();
701
702 DeleteResponseProtocolOp deleteResponse =
703 new DeleteResponseProtocolOp(
704 op.getResultCode().getIntValue(),
705 op.getErrorMessage().toMessage(),
706 op.getMatchedDN(),
707 op.getReferralURLs());
708 ArrayList<LDAPControl> responseControls =
709 new ArrayList<LDAPControl>();
710 for (Control c : op.getResponseControls())
711 {
712 responseControls.add(new LDAPControl(c));
713 }
714
715 socket.getInputStream().addLDAPMessage(
716 new LDAPMessage(messageID, deleteResponse,
717 responseControls));
718 }
719
720
721
722 /**
723 * Processes the content of the provided LDAP message as an extended
724 * operation and returns the appropriate result to the client.
725 *
726 * @param message The LDAP message containing the request to
727 * process.
728 *
729 * @throws IOException If a problem occurs while attempting to
730 * process the operation.
731 */
732 private void processExtendedOperation(LDAPMessage message)
733 throws IOException
734 {
735 int messageID = message.getMessageID();
736 ExtendedRequestProtocolOp request =
737 message.getExtendedRequestProtocolOp();
738 if (request.getOID().equals(OID_START_TLS_REQUEST))
739 {
740 Message m = ERR_INTERNALOS_STARTTLS_NOT_SUPPORTED.get();
741 ExtendedResponseProtocolOp extendedResponse =
742 new ExtendedResponseProtocolOp(
743 LDAPResultCode.UNWILLING_TO_PERFORM, m);
744 socket.getInputStream().addLDAPMessage(
745 new LDAPMessage(messageID, extendedResponse));
746 return;
747 }
748
749 ArrayList<Control> requestControls = new ArrayList<Control>();
750 if (message.getControls() != null)
751 {
752 for (LDAPControl c : message.getControls())
753 {
754 requestControls.add(c.getControl());
755 }
756 }
757
758 InternalClientConnection conn = socket.getConnection();
759 ExtendedOperationBasis op =
760 new ExtendedOperationBasis(conn, conn.nextOperationID(),
761 messageID, requestControls, request.getOID(),
762 request.getValue());
763 op.run();
764
765 ExtendedResponseProtocolOp extendedResponse =
766 new ExtendedResponseProtocolOp(
767 op.getResultCode().getIntValue(),
768 op.getErrorMessage().toMessage(),
769 op.getMatchedDN(),
770 op.getReferralURLs(), op.getResponseOID(),
771 op.getResponseValue());
772 ArrayList<LDAPControl> responseControls =
773 new ArrayList<LDAPControl>();
774 for (Control c : op.getResponseControls())
775 {
776 responseControls.add(new LDAPControl(c));
777 }
778
779 socket.getInputStream().addLDAPMessage(
780 new LDAPMessage(messageID, extendedResponse,
781 responseControls));
782 }
783
784
785
786 /**
787 * Processes the content of the provided LDAP message as a modify
788 * operation and returns the appropriate result to the client.
789 *
790 * @param message The LDAP message containing the request to
791 * process.
792 *
793 * @throws IOException If a problem occurs while attempting to
794 * process the operation.
795 */
796 private void processModifyOperation(LDAPMessage message)
797 throws IOException
798 {
799 int messageID = message.getMessageID();
800 ModifyRequestProtocolOp request =
801 message.getModifyRequestProtocolOp();
802
803 ArrayList<Control> requestControls = new ArrayList<Control>();
804 if (message.getControls() != null)
805 {
806 for (LDAPControl c : message.getControls())
807 {
808 requestControls.add(c.getControl());
809 }
810 }
811
812 InternalClientConnection conn = socket.getConnection();
813 ModifyOperationBasis op =
814 new ModifyOperationBasis(conn, conn.nextOperationID(),
815 messageID, requestControls, request.getDN(),
816 request.getModifications());
817 op.run();
818
819 ModifyResponseProtocolOp modifyResponse =
820 new ModifyResponseProtocolOp(
821 op.getResultCode().getIntValue(),
822 op.getErrorMessage().toMessage(),
823 op.getMatchedDN(),
824 op.getReferralURLs());
825 ArrayList<LDAPControl> responseControls =
826 new ArrayList<LDAPControl>();
827 for (Control c : op.getResponseControls())
828 {
829 responseControls.add(new LDAPControl(c));
830 }
831
832 socket.getInputStream().addLDAPMessage(
833 new LDAPMessage(messageID, modifyResponse,
834 responseControls));
835 }
836
837
838
839 /**
840 * Processes the content of the provided LDAP message as a modify DN
841 * operation and returns the appropriate result to the client.
842 *
843 * @param message The LDAP message containing the request to
844 * process.
845 *
846 * @throws IOException If a problem occurs while attempting to
847 * process the operation.
848 */
849 private void processModifyDNOperation(LDAPMessage message)
850 throws IOException
851 {
852 int messageID = message.getMessageID();
853 ModifyDNRequestProtocolOp request =
854 message.getModifyDNRequestProtocolOp();
855
856 ArrayList<Control> requestControls = new ArrayList<Control>();
857 if (message.getControls() != null)
858 {
859 for (LDAPControl c : message.getControls())
860 {
861 requestControls.add(c.getControl());
862 }
863 }
864
865 InternalClientConnection conn = socket.getConnection();
866 ModifyDNOperationBasis op =
867 new ModifyDNOperationBasis(conn, conn.nextOperationID(),
868 messageID, requestControls, request.getEntryDN(),
869 request.getNewRDN(), request.deleteOldRDN(),
870 request.getNewSuperior());
871 op.run();
872
873 ModifyDNResponseProtocolOp modifyDNResponse =
874 new ModifyDNResponseProtocolOp(
875 op.getResultCode().getIntValue(),
876 op.getErrorMessage().toMessage(),
877 op.getMatchedDN(),
878 op.getReferralURLs());
879 ArrayList<LDAPControl> responseControls =
880 new ArrayList<LDAPControl>();
881 for (Control c : op.getResponseControls())
882 {
883 responseControls.add(new LDAPControl(c));
884 }
885
886 socket.getInputStream().addLDAPMessage(
887 new LDAPMessage(messageID, modifyDNResponse,
888 responseControls));
889 }
890
891
892
893 /**
894 * Processes the content of the provided LDAP message as a search
895 * operation and returns the appropriate result to the client.
896 *
897 * @param message The LDAP message containing the request to
898 * process.
899 *
900 * @throws IOException If a problem occurs while attempting to
901 * process the operation.
902 */
903 private void processSearchOperation(LDAPMessage message)
904 throws IOException
905 {
906 int messageID = message.getMessageID();
907 SearchRequestProtocolOp request =
908 message.getSearchRequestProtocolOp();
909
910 ArrayList<Control> requestControls = new ArrayList<Control>();
911 if (message.getControls() != null)
912 {
913 for (LDAPControl c : message.getControls())
914 {
915 requestControls.add(c.getControl());
916 }
917 }
918
919 InternalClientConnection conn = socket.getConnection();
920 InternalSearchOperation op =
921 new InternalSearchOperation(conn, conn.nextOperationID(),
922 messageID, requestControls, request.getBaseDN(),
923 request.getScope(), request.getDereferencePolicy(),
924 request.getSizeLimit(), request.getTimeLimit(),
925 request.getTypesOnly(), request.getFilter(),
926 request.getAttributes(), this);
927 op.run();
928
929 SearchResultDoneProtocolOp searchDone =
930 new SearchResultDoneProtocolOp(
931 op.getResultCode().getIntValue(),
932 op.getErrorMessage().toMessage(),
933 op.getMatchedDN(),
934 op.getReferralURLs());
935 ArrayList<LDAPControl> responseControls =
936 new ArrayList<LDAPControl>();
937 for (Control c : op.getResponseControls())
938 {
939 responseControls.add(new LDAPControl(c));
940 }
941
942 socket.getInputStream().addLDAPMessage(
943 new LDAPMessage(messageID, searchDone, responseControls));
944 }
945
946
947
948 /**
949 * Performs any processing necessary for the provided search result
950 * entry.
951 *
952 * @param searchOperation The internal search operation being
953 * processed.
954 * @param searchEntry The matching search result entry to be
955 * processed.
956 */
957 @org.opends.server.types.PublicAPI(
958 stability=org.opends.server.types.StabilityLevel.PRIVATE,
959 mayInstantiate=false,
960 mayExtend=false,
961 mayInvoke=false)
962 public void handleInternalSearchEntry(
963 InternalSearchOperation searchOperation,
964 SearchResultEntry searchEntry)
965 {
966 ArrayList<LDAPControl> entryControls =
967 new ArrayList<LDAPControl>();
968 for (Control c : searchEntry.getControls())
969 {
970 entryControls.add(new LDAPControl(c));
971 }
972
973 SearchResultEntryProtocolOp entry =
974 new SearchResultEntryProtocolOp(searchEntry);
975
976 socket.getInputStream().addLDAPMessage(
977 new LDAPMessage(searchOperation.getMessageID(), entry,
978 entryControls));
979 }
980
981
982
983 /**
984 * Performs any processing necessary for the provided search result
985 * reference.
986 *
987 * @param searchOperation The internal search operation being
988 * processed.
989 * @param searchReference The search result reference to be
990 * processed.
991 */
992 @org.opends.server.types.PublicAPI(
993 stability=org.opends.server.types.StabilityLevel.PRIVATE,
994 mayInstantiate=false,
995 mayExtend=false,
996 mayInvoke=false)
997 public void handleInternalSearchReference(
998 InternalSearchOperation searchOperation,
999 SearchResultReference searchReference)
1000 {
1001 ArrayList<LDAPControl> entryControls =
1002 new ArrayList<LDAPControl>();
1003 for (Control c : searchReference.getControls())
1004 {
1005 entryControls.add(new LDAPControl(c));
1006 }
1007
1008 SearchResultReferenceProtocolOp reference =
1009 new SearchResultReferenceProtocolOp(searchReference);
1010
1011 socket.getInputStream().addLDAPMessage(
1012 new LDAPMessage(searchOperation.getMessageID(), reference,
1013 entryControls));
1014 }
1015
1016
1017
1018 /**
1019 * Retrieves a string representation of this internal LDAP socket.
1020 *
1021 * @return A string representation of this internal LDAP socket.
1022 */
1023 @Override()
1024 public String toString()
1025 {
1026 return "InternalLDAPOutputStream";
1027 }
1028 }
1029