InternalLDAPOutputStream.java revision ea1068c292e9b341af6d6b563cd8988a96be20a9
/*
* 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 legal-notices/CDDLv1_0.txt
* 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 legal-notices/CDDLv1_0.txt.
* 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 2009 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS
*/
/**
* 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;
private final ASN1Reader reader;
// The internal LDAP socket with which this output stream is
// associated.
private final InternalLDAPSocket socket;
// The immediate data being written.
private ByteSequenceReader byteBuffer;
// The save buffer used to store any unprocessed data waiting
// to be read as ASN.1 elements. (Usually due to writing incomplete
// ASN.1 elements.)
private final ByteStringBuilder saveBuffer;
private final ByteSequenceReader saveBufferReader;
/**
* An adaptor class for reading from a save buffer and the bytes
* being written sequentially using the InputStream interface.
*
* Since the bytes being written are only available duing the write
* call, any unused data will be appended to the save buffer before
* returning from the write method. This reader will always read the
* save buffer first before the actual bytes being written to ensure
* bytes are read in the same order as they are written.
*/
private class CombinedBufferInputStream extends InputStream
{
/**
* {@inheritDoc}
*/
public int available()
{
// The number of available bytes is the sum of the save buffer
// and the last read data in the NIO ByteStringBuilder.
}
/**
* {@inheritDoc}
*/
public int read()
{
{
// Try saved buffer first
}
{
// Must still be on the channel buffer
}
return -1;
}
/**
* {@inheritDoc}
*/
{
}
/**
* {@inheritDoc}
*/
{
int bytesCopied=0;
int len;
{
// Copy out of the last saved buffer first
bytesCopied += len;
}
{
// Copy out of the channel buffer if we haven't got
// everything we needed.
bytesCopied += len;
}
return bytesCopied;
}
/**
* {@inheritDoc}
*/
{
int bytesSkipped=0;
int len;
{
// Skip in the last saved buffer first
bytesSkipped += len;
}
{
//Skip in the channel buffer if we haven't skipped enough.
(int)length - bytesSkipped);
bytesSkipped += len;
}
return bytesSkipped;
}
}
/**
* 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.
*/
{
this.closed = false;
this.saveBuffer = new ByteStringBuilder();
new CombinedBufferInputStream();
}
/**
* Closes this output stream, its associated socket, and the
* socket's associated input stream.
*/
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.
*/
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.
*/
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.
*/
throws IOException
{
if (closed)
{
throw new IOException(m.toString());
}
try
{
while(reader.elementAvailable())
{
}
}
catch(Exception e)
{
throw new IOException(e.getMessage());
}
// Clear the save buffer if we have read all of it
{
saveBuffer.clear();
}
// Append any unused data in the channel buffer to the save buffer
{
}
}
/**
* 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.
*/
public synchronized void write(int b)
throws IOException
{
}
/**
* 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 message The LDAP message to process.
*
* @throws IOException If a problem occurs while attempting to
* decode the provided ASN.1 element as an
* LDAP message.
*/
throws IOException
{
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());
}
/**
* 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());
{
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());
}
/**
* 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());
}
/**
* 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());
}
/**
* 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());
}
/**
* 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());
}
/**
* 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
{
try
{
}
catch (DirectoryException e)
{
}
op.getMatchedDN(),
op.getReferralURLs());
}
/**
* 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(
{
}
/**
* 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(
{
}
/**
* Retrieves a string representation of this internal LDAP socket.
*
* @return A string representation of this internal LDAP socket.
*/
{
return "InternalLDAPOutputStream";
}
}