InternalLDAPOutputStream.java revision a395dd575518d9e5280fc5d5d5ef47c61b174647
/*
* 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
* 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
*
*
* Copyright 2008 Sun Microsystems, Inc.
*/
/**
* 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.
*/
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.
*/
{
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()
{
}
/**
* Closes this output stream through an internal mechanism that will
* not cause an infinite recursion loop by trying to also close the
* output stream.
*/
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
{
}
/**
* 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()
throws IOException
{
if (closed)
{
throw new IOException(m.toString());
}
if (len == 0)
{
return;
}
// See if we need to read the BER type.
if (needType)
{
elementType = b[position++];
needType = false;
if (--remaining <= 0)
{
return;
}
}
// See if we need to read the first length byte.
{
{
// 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.
}
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.
{
needed);
int length = 0;
for (byte lb : lengthBytes)
{
length <<= 8;
}
elementBytes = new byte[length];
lengthBytes = null;
arrayOffset = 0;
if (remaining <= 0)
{
return;
}
}
else
{
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.
{
needed);
needType = true;
arrayOffset = 0;
lengthBytes = null;
elementBytes = null;
}
else
{
arrayOffset += remaining;
return;
}
}
// If there is still more data available, then call this method
// again to process it.
if (remaining > 0)
{
}
}
/**
* 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)
{
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.
{
// The element has been completed, so process it.
}
lengthBytes = null;
elementBytes = null;
arrayOffset = 0;
needType = true;
return;
}
else if (lengthBytes != null)
{
// The byte should be part of a multi-byte length.
{
int length = 0;
{
length <<= 8;
}
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.
*/
throws IOException
{
try
{
}
catch (Exception e)
{
throw new IOException(e.getMessage());
}
switch (message.getProtocolOpType())
{
case OP_TYPE_ABANDON_REQUEST:
// No action is required.
return;
case OP_TYPE_ADD_REQUEST:
break;
case OP_TYPE_BIND_REQUEST:
break;
case OP_TYPE_COMPARE_REQUEST:
break;
case OP_TYPE_DELETE_REQUEST:
break;
case OP_TYPE_EXTENDED_REQUEST:
break;
case OP_TYPE_MODIFY_REQUEST:
break;
break;
case OP_TYPE_SEARCH_REQUEST:
break;
case OP_TYPE_UNBIND_REQUEST:
break;
default:
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.
*/
throws IOException
{
{
{
}
}
request.getAttributes());
op.getMatchedDN(),
op.getReferralURLs());
new ArrayList<LDAPControl>();
{
}
}
/**
* 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.
*/
throws IOException
{
{
return;
}
{
{
}
}
op.getMatchedDN(),
op.getReferralURLs());
new ArrayList<LDAPControl>();
{
}
{
op.getAuthenticationInfo()));
}
}
/**
* 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.
*/
throws IOException
{
{
{
}
}
op.getMatchedDN(),
op.getReferralURLs());
new ArrayList<LDAPControl>();
{
}
}
/**
* 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.
*/
throws IOException
{
{
{
}
}
op.getMatchedDN(),
op.getReferralURLs());
new ArrayList<LDAPControl>();
{
}
}
/**
* 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.
*/
throws IOException
{
{
return;
}
{
{
}
}
op.getMatchedDN(),
op.getResponseValue());
new ArrayList<LDAPControl>();
{
}
}
/**
* 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.
*/
throws IOException
{
{
{
}
}
op.getMatchedDN(),
op.getReferralURLs());
new ArrayList<LDAPControl>();
{
}
}
/**
* 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.
*/
throws IOException
{
{
{
}
}
op.getMatchedDN(),
op.getReferralURLs());
new ArrayList<LDAPControl>();
{
}
}
/**
* 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.
*/
throws IOException
{
{
{
}
}
request.getAttributes(), this);
op.getMatchedDN(),
op.getReferralURLs());
new ArrayList<LDAPControl>();
{
}
}
/**
* 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.
*/
mayInstantiate=false,
mayExtend=false,
mayInvoke=false)
public void handleInternalSearchEntry(
{
new ArrayList<LDAPControl>();
{
}
}
/**
* 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.
*/
mayInstantiate=false,
mayExtend=false,
mayInvoke=false)
public void handleInternalSearchReference(
{
new ArrayList<LDAPControl>();
{
}
}
/**
* Retrieves a string representation of this internal LDAP socket.
*
* @return A string representation of this internal LDAP socket.
*/
@Override()
{
return "InternalLDAPOutputStream";
}
}