/*
|
* CDDL HEADER START
|
*
|
* The contents of this file are subject to the terms of the
|
* Common Development and Distribution License, Version 1.0 only
|
* (the "License"). You may not use this file except in compliance
|
* with the License.
|
*
|
* You can obtain a copy of the license at
|
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
|
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
|
* See the License for the specific language governing permissions
|
* and limitations under the License.
|
*
|
* When distributing Covered Code, include this CDDL HEADER in each
|
* file and include the License file at
|
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
|
* add the following below this CDDL HEADER, with the fields enclosed
|
* by brackets "[]" replaced with your own identifying information:
|
* Portions Copyright [yyyy] [name of copyright owner]
|
*
|
* CDDL HEADER END
|
*
|
*
|
* Portions Copyright 2007 Sun Microsystems, Inc.
|
*/
|
package org.opends.server.protocols.internal;
|
|
|
|
import java.io.OutputStream;
|
import java.io.IOException;
|
import java.util.ArrayList;
|
|
import org.opends.messages.Message;
|
import org.opends.server.core.*;
|
import org.opends.server.protocols.asn1.ASN1Element;
|
import org.opends.server.protocols.ldap.*;
|
import org.opends.server.types.AuthenticationType;
|
import org.opends.server.types.Control;
|
import org.opends.server.types.SearchResultEntry;
|
import org.opends.server.types.SearchResultReference;
|
|
import static org.opends.messages.ProtocolMessages.*;
|
import static org.opends.server.protocols.ldap.LDAPConstants.*;
|
import static org.opends.server.util.ServerConstants.*;
|
|
|
|
/**
|
* This class provides an implementation of a
|
* {@code java.io.OutputStream} that can be used to facilitate
|
* internal communication with the Directory Server. On the backend,
|
* data written to this output stream will be first decoded as an
|
* ASN.1 element and then as an LDAP message. That LDAP message will
|
* be converted to an internal operation which will then be processed
|
* and the result returned to the client via the input stream on the
|
* other side of the associated internal LDAP socket.
|
*/
|
@org.opends.server.types.PublicAPI(
|
stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
|
mayInstantiate=false,
|
mayExtend=false,
|
mayInvoke=true)
|
public final class InternalLDAPOutputStream
|
extends OutputStream
|
implements InternalSearchListener
|
{
|
// Indicates whether this stream has been closed.
|
private boolean closed;
|
|
// Indicates whether the type of the ASN.1 element is needed.
|
private boolean needType;
|
|
// The BER type for the ASN.1 element being read.
|
private byte elementType;
|
|
// The data for the ASN.1 element being read.
|
private byte[] elementBytes;
|
|
// The length bytes for the ASN.1 element being read.
|
private byte[] lengthBytes;
|
|
// The offset in the appropriate array at which we should begin
|
// writing data. This could either refer to the length or data
|
// array, depending on the stage of the encoding process.
|
private int arrayOffset;
|
|
// The internal LDAP socket with which this output stream is
|
// associated.
|
private InternalLDAPSocket socket;
|
|
|
|
/**
|
* Creates a new instance of an internal LDAP output stream that is
|
* associated with the provided internal LDAP socket.
|
*
|
* @param socket The internal LDAP socket that will be serviced by
|
* this internal LDAP output stream.
|
*/
|
public InternalLDAPOutputStream(InternalLDAPSocket socket)
|
{
|
this.socket = socket;
|
|
closed = false;
|
|
needType = true;
|
elementType = 0x00;
|
elementBytes = null;
|
lengthBytes = null;
|
arrayOffset = 0;
|
}
|
|
|
|
/**
|
* Closes this output stream, its associated socket, and the
|
* socket's associated input stream.
|
*/
|
@Override()
|
public void close()
|
{
|
socket.close();
|
}
|
|
|
|
/**
|
* Closes this output stream through an internal mechanism that will
|
* not cause an infinite recursion loop by trying to also close the
|
* output stream.
|
*/
|
@org.opends.server.types.PublicAPI(
|
stability=org.opends.server.types.StabilityLevel.PRIVATE,
|
mayInstantiate=false,
|
mayExtend=false,
|
mayInvoke=false)
|
void closeInternal()
|
{
|
closed = true;
|
}
|
|
|
|
/**
|
* Flushes this output stream and forces any buffered data to be
|
* written out. This will have no effect, since this output
|
* stream implementation does not use buffering.
|
*/
|
@Override()
|
public void flush()
|
{
|
// No implementation is required.
|
}
|
|
|
|
/**
|
* Writes the contents of the provided byte array to this output
|
* stream.
|
*
|
* @param b The byte array to be written.
|
*
|
* @throws IOException If the output stream is closed, or if there
|
* is a problem with the data being written.
|
*/
|
@Override()
|
public void write(byte[] b)
|
throws IOException
|
{
|
write(b, 0, b.length);
|
}
|
|
|
|
/**
|
* Writes the specified portion of the data in the provided byte
|
* array to this output stream. Any data written will be
|
* accumulated until a complete ASN.1 element is available, at which
|
* point it will be decoded as an LDAP message and converted to an
|
* internal operation that will be processed.
|
*
|
* @param b The byte array containing the data to be read.
|
* @param off The position in the array at which to start reading
|
* data.
|
* @param len The number of bytes to read from the array.
|
*
|
* @throws IOException If the output stream is closed, or if there
|
* is a problem with the data being written.
|
*/
|
@Override()
|
public synchronized void write(byte[] b, int off, int len)
|
throws IOException
|
{
|
if (closed)
|
{
|
Message m = ERR_INTERNALOS_CLOSED.get();
|
throw new IOException(m.toString());
|
}
|
|
if (len == 0)
|
{
|
return;
|
}
|
|
|
// See if we need to read the BER type.
|
int position = off;
|
int remaining = len;
|
if (needType)
|
{
|
elementType = b[position++];
|
needType = false;
|
|
if (--remaining <= 0)
|
{
|
return;
|
}
|
}
|
|
|
// See if we need to read the first length byte.
|
if ((lengthBytes == null) && (elementBytes == null))
|
{
|
int length = b[position++];
|
if (length == (length & 0x7F))
|
{
|
// It's a single-byte length, so we can create the value
|
// array.
|
elementBytes = new byte[length];
|
}
|
else
|
{
|
// It's a multi-byte length, so we can create the length
|
// array.
|
lengthBytes = new byte[length & 0x7F];
|
}
|
|
arrayOffset = 0;
|
if (--remaining <= 0)
|
{
|
return;
|
}
|
}
|
|
|
// See if we need to continue reading part of a multi-byte length.
|
if (lengthBytes != null)
|
{
|
// See if we have enough to read the full length. If so, then
|
// do it. Otherwise, read what we can and return.
|
int needed = lengthBytes.length - arrayOffset;
|
if (remaining >= needed)
|
{
|
System.arraycopy(b, position, lengthBytes, arrayOffset,
|
needed);
|
position += needed;
|
remaining -= needed;
|
|
int length = 0;
|
for (byte lb : lengthBytes)
|
{
|
length <<= 8;
|
length |= (lb & 0xFF);
|
}
|
|
elementBytes = new byte[length];
|
lengthBytes = null;
|
arrayOffset = 0;
|
if (remaining <= 0)
|
{
|
return;
|
}
|
}
|
else
|
{
|
System.arraycopy(b, position, lengthBytes, arrayOffset,
|
remaining);
|
arrayOffset += remaining;
|
return;
|
}
|
}
|
|
|
// See if we need to read data for the element value.
|
if (elementBytes != null)
|
{
|
// See if we have enough to read the full value. If so, then
|
// do it, create the element, and process it. Otherwise, read
|
// what we can and return.
|
int needed = elementBytes.length - arrayOffset;
|
if (remaining >= needed)
|
{
|
System.arraycopy(b, position, elementBytes, arrayOffset,
|
needed);
|
position += needed;
|
remaining -= needed;
|
processElement(new ASN1Element(elementType, elementBytes));
|
|
needType = true;
|
arrayOffset = 0;
|
lengthBytes = null;
|
elementBytes = null;
|
}
|
else
|
{
|
System.arraycopy(b, position, lengthBytes, arrayOffset,
|
remaining);
|
arrayOffset += remaining;
|
return;
|
}
|
}
|
|
|
// If there is still more data available, then call this method
|
// again to process it.
|
if (remaining > 0)
|
{
|
write(b, position, remaining);
|
}
|
}
|
|
|
|
/**
|
* Writes a single byte of data to this output stream. If the byte
|
* written completes an ASN.1 element that was in progress, then it
|
* will be decoded as an LDAP message and converted to an internal
|
* operation that will be processed. Otherwise, the data will be
|
* accumulated until a complete element can be formed.
|
*
|
* @param b The byte to be written.
|
*
|
* @throws IOException If the output stream is closed, or if there
|
* is a problem with the data being written.
|
*/
|
@Override()
|
public synchronized void write(int b)
|
throws IOException
|
{
|
if (closed)
|
{
|
Message m = ERR_INTERNALOS_CLOSED.get();
|
throw new IOException(m.toString());
|
}
|
|
if (needType)
|
{
|
elementType = (byte) (b & 0xFF);
|
needType = false;
|
return;
|
}
|
else if (elementBytes != null)
|
{
|
// The byte should be part of the element value.
|
elementBytes[arrayOffset++] = (byte) (b & 0xFF);
|
if (arrayOffset == elementBytes.length)
|
{
|
// The element has been completed, so process it.
|
processElement(new ASN1Element(elementType, elementBytes));
|
}
|
|
lengthBytes = null;
|
elementBytes = null;
|
arrayOffset = 0;
|
needType = true;
|
|
return;
|
}
|
else if (lengthBytes != null)
|
{
|
// The byte should be part of a multi-byte length.
|
lengthBytes[arrayOffset++] = (byte) (b & 0xFF);
|
if (arrayOffset == lengthBytes.length)
|
{
|
int length = 0;
|
for (int i=0; i < lengthBytes.length; i++)
|
{
|
length <<= 8;
|
length |= (lengthBytes[i] & 0xFF);
|
}
|
|
elementBytes = new byte[length];
|
lengthBytes = null;
|
arrayOffset = 0;
|
}
|
|
return;
|
}
|
else
|
{
|
if ((b & 0x7F) == b)
|
{
|
// It's the complete length.
|
elementBytes = new byte[b];
|
lengthBytes = null;
|
arrayOffset = 0;
|
}
|
else
|
{
|
lengthBytes = new byte[b & 0x7F];
|
elementBytes = null;
|
arrayOffset = 0;
|
}
|
|
return;
|
}
|
}
|
|
|
|
/**
|
* Processes the provided ASN.1 element by decoding it as an LDAP
|
* message, converting that to an internal operation, and sending
|
* the appropriate response message(s) to the client through the
|
* corresponding internal LDAP input stream.
|
*
|
* @param element The ASN.1 element to be processed.
|
*
|
* @throws IOException If a problem occurs while attempting to
|
* decode the provided ASN.1 element as an
|
* LDAP message.
|
*/
|
private void processElement(ASN1Element element)
|
throws IOException
|
{
|
LDAPMessage message;
|
try
|
{
|
message = LDAPMessage.decode(element.decodeAsSequence());
|
}
|
catch (Exception e)
|
{
|
throw new IOException(e.getMessage(), e);
|
}
|
|
switch (message.getProtocolOpType())
|
{
|
case OP_TYPE_ABANDON_REQUEST:
|
// No action is required.
|
return;
|
|
case OP_TYPE_ADD_REQUEST:
|
processAddOperation(message);
|
break;
|
|
case OP_TYPE_BIND_REQUEST:
|
processBindOperation(message);
|
break;
|
|
case OP_TYPE_COMPARE_REQUEST:
|
processCompareOperation(message);
|
break;
|
|
|
case OP_TYPE_DELETE_REQUEST:
|
processDeleteOperation(message);
|
break;
|
|
|
case OP_TYPE_EXTENDED_REQUEST:
|
processExtendedOperation(message);
|
break;
|
|
|
case OP_TYPE_MODIFY_REQUEST:
|
processModifyOperation(message);
|
break;
|
|
|
case OP_TYPE_MODIFY_DN_REQUEST:
|
processModifyDNOperation(message);
|
break;
|
|
|
case OP_TYPE_SEARCH_REQUEST:
|
processSearchOperation(message);
|
break;
|
|
|
case OP_TYPE_UNBIND_REQUEST:
|
socket.close();
|
break;
|
|
|
default:
|
Message m = ERR_INTERNALOS_INVALID_REQUEST.get(
|
message.getProtocolElementName());
|
throw new IOException(m.toString());
|
}
|
}
|
|
|
|
/**
|
* Processes the content of the provided LDAP message as an add
|
* operation and returns the appropriate result to the client.
|
*
|
* @param message The LDAP message containing the request to
|
* process.
|
*
|
* @throws IOException If a problem occurs while attempting to
|
* process the operation.
|
*/
|
private void processAddOperation(LDAPMessage message)
|
throws IOException
|
{
|
int messageID = message.getMessageID();
|
AddRequestProtocolOp request = message.getAddRequestProtocolOp();
|
|
ArrayList<Control> requestControls = new ArrayList<Control>();
|
if (message.getControls() != null)
|
{
|
for (LDAPControl c : message.getControls())
|
{
|
requestControls.add(c.getControl());
|
}
|
}
|
|
InternalClientConnection conn = socket.getConnection();
|
AddOperationBasis op =
|
new AddOperationBasis(conn, conn.nextOperationID(),
|
messageID, requestControls,
|
request.getDN(),
|
request.getAttributes());
|
op.run();
|
|
AddResponseProtocolOp addResponse =
|
new AddResponseProtocolOp(op.getResultCode().getIntValue(),
|
op.getErrorMessage().toMessage(),
|
op.getMatchedDN(),
|
op.getReferralURLs());
|
ArrayList<LDAPControl> responseControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : op.getResponseControls())
|
{
|
responseControls.add(new LDAPControl(c));
|
}
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, addResponse, responseControls));
|
}
|
|
|
|
/**
|
* Processes the content of the provided LDAP message as a bind
|
* operation and returns the appropriate result to the client.
|
*
|
* @param message The LDAP message containing the request to
|
* process.
|
*
|
* @throws IOException If a problem occurs while attempting to
|
* process the operation.
|
*/
|
private void processBindOperation(LDAPMessage message)
|
throws IOException
|
{
|
int messageID = message.getMessageID();
|
BindRequestProtocolOp request =
|
message.getBindRequestProtocolOp();
|
|
if (request.getAuthenticationType() == AuthenticationType.SASL)
|
{
|
Message m = ERR_INTERNALOS_SASL_BIND_NOT_SUPPORTED.get();
|
BindResponseProtocolOp bindResponse =
|
new BindResponseProtocolOp(
|
LDAPResultCode.UNWILLING_TO_PERFORM, m);
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, bindResponse));
|
return;
|
}
|
|
ArrayList<Control> requestControls = new ArrayList<Control>();
|
if (message.getControls() != null)
|
{
|
for (LDAPControl c : message.getControls())
|
{
|
requestControls.add(c.getControl());
|
}
|
}
|
|
InternalClientConnection conn = socket.getConnection();
|
BindOperationBasis op =
|
new BindOperationBasis(conn, conn.nextOperationID(),
|
messageID, requestControls,
|
String.valueOf(request.getProtocolVersion()),
|
request.getDN(), request.getSimplePassword());
|
op.run();
|
|
BindResponseProtocolOp bindResponse =
|
new BindResponseProtocolOp(op.getResultCode().getIntValue(),
|
op.getErrorMessage().toMessage(),
|
op.getMatchedDN(),
|
op.getReferralURLs());
|
ArrayList<LDAPControl> responseControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : op.getResponseControls())
|
{
|
responseControls.add(new LDAPControl(c));
|
}
|
|
if (bindResponse.getResultCode() == LDAPResultCode.SUCCESS)
|
{
|
socket.setConnection(new InternalClientConnection(
|
op.getAuthenticationInfo()));
|
}
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, bindResponse, responseControls));
|
}
|
|
|
|
/**
|
* Processes the content of the provided LDAP message as a compare
|
* operation and returns the appropriate result to the client.
|
*
|
* @param message The LDAP message containing the request to
|
* process.
|
*
|
* @throws IOException If a problem occurs while attempting to
|
* process the operation.
|
*/
|
private void processCompareOperation(LDAPMessage message)
|
throws IOException
|
{
|
int messageID = message.getMessageID();
|
CompareRequestProtocolOp request =
|
message.getCompareRequestProtocolOp();
|
|
ArrayList<Control> requestControls = new ArrayList<Control>();
|
if (message.getControls() != null)
|
{
|
for (LDAPControl c : message.getControls())
|
{
|
requestControls.add(c.getControl());
|
}
|
}
|
|
InternalClientConnection conn = socket.getConnection();
|
CompareOperationBasis op =
|
new CompareOperationBasis(conn, conn.nextOperationID(),
|
messageID, requestControls, request.getDN(),
|
request.getAttributeType(),
|
request.getAssertionValue());
|
op.run();
|
|
CompareResponseProtocolOp compareResponse =
|
new CompareResponseProtocolOp(
|
op.getResultCode().getIntValue(),
|
op.getErrorMessage().toMessage(),
|
op.getMatchedDN(),
|
op.getReferralURLs());
|
ArrayList<LDAPControl> responseControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : op.getResponseControls())
|
{
|
responseControls.add(new LDAPControl(c));
|
}
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, compareResponse,
|
responseControls));
|
}
|
|
|
|
/**
|
* Processes the content of the provided LDAP message as a delete
|
* operation and returns the appropriate result to the client.
|
*
|
* @param message The LDAP message containing the request to
|
* process.
|
*
|
* @throws IOException If a problem occurs while attempting to
|
* process the operation.
|
*/
|
private void processDeleteOperation(LDAPMessage message)
|
throws IOException
|
{
|
int messageID = message.getMessageID();
|
DeleteRequestProtocolOp request =
|
message.getDeleteRequestProtocolOp();
|
|
ArrayList<Control> requestControls = new ArrayList<Control>();
|
if (message.getControls() != null)
|
{
|
for (LDAPControl c : message.getControls())
|
{
|
requestControls.add(c.getControl());
|
}
|
}
|
|
InternalClientConnection conn = socket.getConnection();
|
DeleteOperationBasis op =
|
new DeleteOperationBasis(conn, conn.nextOperationID(),
|
messageID, requestControls, request.getDN());
|
op.run();
|
|
DeleteResponseProtocolOp deleteResponse =
|
new DeleteResponseProtocolOp(
|
op.getResultCode().getIntValue(),
|
op.getErrorMessage().toMessage(),
|
op.getMatchedDN(),
|
op.getReferralURLs());
|
ArrayList<LDAPControl> responseControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : op.getResponseControls())
|
{
|
responseControls.add(new LDAPControl(c));
|
}
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, deleteResponse,
|
responseControls));
|
}
|
|
|
|
/**
|
* Processes the content of the provided LDAP message as an extended
|
* operation and returns the appropriate result to the client.
|
*
|
* @param message The LDAP message containing the request to
|
* process.
|
*
|
* @throws IOException If a problem occurs while attempting to
|
* process the operation.
|
*/
|
private void processExtendedOperation(LDAPMessage message)
|
throws IOException
|
{
|
int messageID = message.getMessageID();
|
ExtendedRequestProtocolOp request =
|
message.getExtendedRequestProtocolOp();
|
if (request.getOID().equals(OID_START_TLS_REQUEST))
|
{
|
Message m = ERR_INTERNALOS_STARTTLS_NOT_SUPPORTED.get();
|
ExtendedResponseProtocolOp extendedResponse =
|
new ExtendedResponseProtocolOp(
|
LDAPResultCode.UNWILLING_TO_PERFORM, m);
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, extendedResponse));
|
return;
|
}
|
|
ArrayList<Control> requestControls = new ArrayList<Control>();
|
if (message.getControls() != null)
|
{
|
for (LDAPControl c : message.getControls())
|
{
|
requestControls.add(c.getControl());
|
}
|
}
|
|
InternalClientConnection conn = socket.getConnection();
|
ExtendedOperationBasis op =
|
new ExtendedOperationBasis(conn, conn.nextOperationID(),
|
messageID, requestControls, request.getOID(),
|
request.getValue());
|
op.run();
|
|
ExtendedResponseProtocolOp extendedResponse =
|
new ExtendedResponseProtocolOp(
|
op.getResultCode().getIntValue(),
|
op.getErrorMessage().toMessage(),
|
op.getMatchedDN(),
|
op.getReferralURLs(), op.getResponseOID(),
|
op.getResponseValue());
|
ArrayList<LDAPControl> responseControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : op.getResponseControls())
|
{
|
responseControls.add(new LDAPControl(c));
|
}
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, extendedResponse,
|
responseControls));
|
}
|
|
|
|
/**
|
* Processes the content of the provided LDAP message as a modify
|
* operation and returns the appropriate result to the client.
|
*
|
* @param message The LDAP message containing the request to
|
* process.
|
*
|
* @throws IOException If a problem occurs while attempting to
|
* process the operation.
|
*/
|
private void processModifyOperation(LDAPMessage message)
|
throws IOException
|
{
|
int messageID = message.getMessageID();
|
ModifyRequestProtocolOp request =
|
message.getModifyRequestProtocolOp();
|
|
ArrayList<Control> requestControls = new ArrayList<Control>();
|
if (message.getControls() != null)
|
{
|
for (LDAPControl c : message.getControls())
|
{
|
requestControls.add(c.getControl());
|
}
|
}
|
|
InternalClientConnection conn = socket.getConnection();
|
ModifyOperationBasis op =
|
new ModifyOperationBasis(conn, conn.nextOperationID(),
|
messageID, requestControls, request.getDN(),
|
request.getModifications());
|
op.run();
|
|
ModifyResponseProtocolOp modifyResponse =
|
new ModifyResponseProtocolOp(
|
op.getResultCode().getIntValue(),
|
op.getErrorMessage().toMessage(),
|
op.getMatchedDN(),
|
op.getReferralURLs());
|
ArrayList<LDAPControl> responseControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : op.getResponseControls())
|
{
|
responseControls.add(new LDAPControl(c));
|
}
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, modifyResponse,
|
responseControls));
|
}
|
|
|
|
/**
|
* Processes the content of the provided LDAP message as a modify DN
|
* operation and returns the appropriate result to the client.
|
*
|
* @param message The LDAP message containing the request to
|
* process.
|
*
|
* @throws IOException If a problem occurs while attempting to
|
* process the operation.
|
*/
|
private void processModifyDNOperation(LDAPMessage message)
|
throws IOException
|
{
|
int messageID = message.getMessageID();
|
ModifyDNRequestProtocolOp request =
|
message.getModifyDNRequestProtocolOp();
|
|
ArrayList<Control> requestControls = new ArrayList<Control>();
|
if (message.getControls() != null)
|
{
|
for (LDAPControl c : message.getControls())
|
{
|
requestControls.add(c.getControl());
|
}
|
}
|
|
InternalClientConnection conn = socket.getConnection();
|
ModifyDNOperationBasis op =
|
new ModifyDNOperationBasis(conn, conn.nextOperationID(),
|
messageID, requestControls, request.getEntryDN(),
|
request.getNewRDN(), request.deleteOldRDN(),
|
request.getNewSuperior());
|
op.run();
|
|
ModifyDNResponseProtocolOp modifyDNResponse =
|
new ModifyDNResponseProtocolOp(
|
op.getResultCode().getIntValue(),
|
op.getErrorMessage().toMessage(),
|
op.getMatchedDN(),
|
op.getReferralURLs());
|
ArrayList<LDAPControl> responseControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : op.getResponseControls())
|
{
|
responseControls.add(new LDAPControl(c));
|
}
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, modifyDNResponse,
|
responseControls));
|
}
|
|
|
|
/**
|
* Processes the content of the provided LDAP message as a search
|
* operation and returns the appropriate result to the client.
|
*
|
* @param message The LDAP message containing the request to
|
* process.
|
*
|
* @throws IOException If a problem occurs while attempting to
|
* process the operation.
|
*/
|
private void processSearchOperation(LDAPMessage message)
|
throws IOException
|
{
|
int messageID = message.getMessageID();
|
SearchRequestProtocolOp request =
|
message.getSearchRequestProtocolOp();
|
|
ArrayList<Control> requestControls = new ArrayList<Control>();
|
if (message.getControls() != null)
|
{
|
for (LDAPControl c : message.getControls())
|
{
|
requestControls.add(c.getControl());
|
}
|
}
|
|
InternalClientConnection conn = socket.getConnection();
|
InternalSearchOperation op =
|
new InternalSearchOperation(conn, conn.nextOperationID(),
|
messageID, requestControls, request.getBaseDN(),
|
request.getScope(), request.getDereferencePolicy(),
|
request.getSizeLimit(), request.getTimeLimit(),
|
request.getTypesOnly(), request.getFilter(),
|
request.getAttributes(), this);
|
op.run();
|
|
SearchResultDoneProtocolOp searchDone =
|
new SearchResultDoneProtocolOp(
|
op.getResultCode().getIntValue(),
|
op.getErrorMessage().toMessage(),
|
op.getMatchedDN(),
|
op.getReferralURLs());
|
ArrayList<LDAPControl> responseControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : op.getResponseControls())
|
{
|
responseControls.add(new LDAPControl(c));
|
}
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(messageID, searchDone, responseControls));
|
}
|
|
|
|
/**
|
* Performs any processing necessary for the provided search result
|
* entry.
|
*
|
* @param searchOperation The internal search operation being
|
* processed.
|
* @param searchEntry The matching search result entry to be
|
* processed.
|
*/
|
@org.opends.server.types.PublicAPI(
|
stability=org.opends.server.types.StabilityLevel.PRIVATE,
|
mayInstantiate=false,
|
mayExtend=false,
|
mayInvoke=false)
|
public void handleInternalSearchEntry(
|
InternalSearchOperation searchOperation,
|
SearchResultEntry searchEntry)
|
{
|
ArrayList<LDAPControl> entryControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : searchEntry.getControls())
|
{
|
entryControls.add(new LDAPControl(c));
|
}
|
|
SearchResultEntryProtocolOp entry =
|
new SearchResultEntryProtocolOp(searchEntry);
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(searchOperation.getMessageID(), entry,
|
entryControls));
|
}
|
|
|
|
/**
|
* Performs any processing necessary for the provided search result
|
* reference.
|
*
|
* @param searchOperation The internal search operation being
|
* processed.
|
* @param searchReference The search result reference to be
|
* processed.
|
*/
|
@org.opends.server.types.PublicAPI(
|
stability=org.opends.server.types.StabilityLevel.PRIVATE,
|
mayInstantiate=false,
|
mayExtend=false,
|
mayInvoke=false)
|
public void handleInternalSearchReference(
|
InternalSearchOperation searchOperation,
|
SearchResultReference searchReference)
|
{
|
ArrayList<LDAPControl> entryControls =
|
new ArrayList<LDAPControl>();
|
for (Control c : searchReference.getControls())
|
{
|
entryControls.add(new LDAPControl(c));
|
}
|
|
SearchResultReferenceProtocolOp reference =
|
new SearchResultReferenceProtocolOp(searchReference);
|
|
socket.getInputStream().addLDAPMessage(
|
new LDAPMessage(searchOperation.getMessageID(), reference,
|
entryControls));
|
}
|
|
|
|
/**
|
* Retrieves a string representation of this internal LDAP socket.
|
*
|
* @return A string representation of this internal LDAP socket.
|
*/
|
@Override()
|
public String toString()
|
{
|
return "InternalLDAPOutputStream";
|
}
|
}
|