blob: d0204c77b89c56032ced033504aef1d7da8a3cdb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.shared.ldap.codec.search;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;
import javax.naming.NamingException;
import org.apache.directory.shared.asn1.ber.tlv.TLV;
import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
import org.apache.directory.shared.asn1.ber.tlv.Value;
import org.apache.directory.shared.asn1.codec.EncoderException;
import org.apache.directory.shared.asn1.util.Asn1StringUtils;
import org.apache.directory.shared.ldap.codec.LdapConstants;
import org.apache.directory.shared.ldap.codec.LdapMessageCodec;
import org.apache.directory.shared.ldap.entry.Entry;
import org.apache.directory.shared.ldap.entry.EntryAttribute;
import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
import org.apache.directory.shared.ldap.entry.client.DefaultClientEntry;
import org.apache.directory.shared.ldap.name.LdapDN;
import org.apache.directory.shared.ldap.util.StringTools;
/**
* A SearchResultEntry Message. Its syntax is :
* SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
* objectName LDAPDN,
* attributes PartialAttributeList }
*
* PartialAttributeList ::= SEQUENCE OF SEQUENCE {
* type AttributeDescription,
* vals SET OF AttributeValue }
*
* AttributeDescription ::= LDAPString
*
* AttributeValue ::= OCTET STRING
*
* It contains an entry, with all its attributes, and all the attributes
* values. If a search request is submited, all the results are sent one
* by one, followed by a searchResultDone message.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$, $Date$,
*/
public class SearchResultEntryCodec extends LdapMessageCodec
{
// ~ Instance fields
// ----------------------------------------------------------------------------
/** A temporary storage for the byte[] representing the objectName */
private byte[] objectNameBytes;
/** The entry */
private Entry entry = new DefaultClientEntry();
/** The current attribute being decoded */
private EntryAttribute currentAttributeValue;
/** The search result entry length */
private int searchResultEntryLength;
/** The partial attributes length */
private int attributesLength;
/** The list of all attributes length */
private List<Integer> attributeLength;
/** The list of all vals length */
private List<Integer> valsLength;
// ~ Constructors
// -------------------------------------------------------------------------------
/**
* Creates a new SearchResultEntry object.
*/
public SearchResultEntryCodec()
{
super();
}
// ~ Methods
// ------------------------------------------------------------------------------------
/**
* Get the message type
*
* @return Returns the type.
*/
public int getMessageType()
{
return LdapConstants.SEARCH_RESULT_ENTRY;
}
/**
* Get the entry DN
*
* @return Returns the objectName.
*/
public LdapDN getObjectName()
{
return entry.getDn();
}
/**
* Set the entry DN.
*
* @param objectName The objectName to set.
*/
public void setObjectName( LdapDN objectName )
{
entry.setDn( objectName );
}
/**
* Get the entry.
*
* @return Returns the entry
*/
public Entry getEntry()
{
return entry;
}
/**
* Sets the entry.
*
* @param entry
* the entry
*/
public void setEntry( Entry entry )
{
this.entry = entry;
}
/**
* Create a new attributeValue
*
* @param type The attribute's name
*/
public void addAttributeValues( String type )
{
currentAttributeValue = new DefaultClientAttribute( type );
try
{
entry.put( currentAttributeValue );
}
catch ( NamingException ne )
{
// Too bad... But there is nothing we can do.
}
}
/**
* Add a new value to the current attribute
*
* @param value
*/
public void addAttributeValue( Object value )
{
if ( value instanceof String )
{
currentAttributeValue.add( ( String ) value );
}
else
{
currentAttributeValue.add( ( byte[] ) value );
}
}
/**
* Compute the SearchResultEntry length
*
* SearchResultEntry :
*
* 0x64 L1
* |
* +--> 0x04 L2 objectName
* +--> 0x30 L3 (attributes)
* |
* +--> 0x30 L4-1 (partial attributes list)
* | |
* | +--> 0x04 L5-1 type
* | +--> 0x31 L6-1 (values)
* | |
* | +--> 0x04 L7-1-1 value
* | +--> ...
* | +--> 0x04 L7-1-n value
* |
* +--> 0x30 L4-2 (partial attributes list)
* | |
* | +--> 0x04 L5-2 type
* | +--> 0x31 L6-2 (values)
* | |
* | +--> 0x04 L7-2-1 value
* | +--> ...
* | +--> 0x04 L7-2-n value
* |
* +--> ...
* |
* +--> 0x30 L4-m (partial attributes list)
* |
* +--> 0x04 L5-m type
* +--> 0x31 L6-m (values)
* |
* +--> 0x04 L7-m-1 value
* +--> ...
* +--> 0x04 L7-m-n value
*
*/
public int computeLength()
{
objectNameBytes = StringTools.getBytesUtf8( entry.getDn().getName() );
// The entry
searchResultEntryLength = 1 + TLV.getNbBytes( objectNameBytes.length ) + objectNameBytes.length;
// The attributes sequence
attributesLength = 0;
if ( ( entry != null ) && ( entry.size() != 0 ) )
{
attributeLength = new LinkedList<Integer>();
valsLength = new LinkedList<Integer>();
// Compute the attributes length
for ( EntryAttribute attribute : entry )
{
int localAttributeLength = 0;
int localValuesLength = 0;
// Get the type length
int idLength = attribute.getId().getBytes().length;
localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength;
if ( attribute.size() != 0 )
{
// The values
if ( attribute.size() > 0 )
{
localValuesLength = 0;
for ( org.apache.directory.shared.ldap.entry.Value<?> value : attribute )
{
byte[] binaryValue = value.getBytes();
localValuesLength += 1 + TLV.getNbBytes( binaryValue.length ) + binaryValue.length;
}
localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength;
}
else
{
// We have to deal with the special wase where
// we don't have a value.
// It will be encoded as an empty OCTETSTRING,
// so it will be two byte slong (0x04 0x00)
localAttributeLength += 1 + 1;
}
}
else
{
// We have no values. We will just have an empty SET OF :
// 0x31 0x00
localAttributeLength += 1 + 1;
}
// add the attribute length to the attributes length
attributesLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength;
attributeLength.add( localAttributeLength );
valsLength.add( localValuesLength );
}
}
searchResultEntryLength += 1 + TLV.getNbBytes( attributesLength ) + attributesLength;
// Return the result.
return 1 + TLV.getNbBytes( searchResultEntryLength ) + searchResultEntryLength;
}
/**
* Encode the SearchResultEntry message to a PDU.
*
* SearchResultEntry :
*
* 0x64 LL
* 0x04 LL objectName
* 0x30 LL attributes
* 0x30 LL partialAttributeList
* 0x04 LL type
* 0x31 LL vals
* 0x04 LL attributeValue
* ...
* 0x04 LL attributeValue
* ...
* 0x30 LL partialAttributeList
* 0x04 LL type
* 0x31 LL vals
* 0x04 LL attributeValue
* ...
* 0x04 LL attributeValue
*
* @param buffer The buffer where to put the PDU
* @return The PDU.
*/
public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
{
if ( buffer == null )
{
throw new EncoderException( "Cannot put a PDU in a null buffer !" );
}
try
{
// The SearchResultEntry Tag
buffer.put( LdapConstants.SEARCH_RESULT_ENTRY_TAG );
buffer.put( TLV.getBytes( searchResultEntryLength ) );
// The objectName
Value.encode( buffer, objectNameBytes );
// The attributes sequence
buffer.put( UniversalTag.SEQUENCE_TAG );
buffer.put( TLV.getBytes( attributesLength ) );
// The partial attribute list
if ( ( entry != null ) && ( entry.size() != 0 ) )
{
int attributeNumber = 0;
// Compute the attributes length
for ( EntryAttribute attribute : entry )
{
// The partial attribute list sequence
buffer.put( UniversalTag.SEQUENCE_TAG );
int localAttributeLength = attributeLength.get( attributeNumber );
buffer.put( TLV.getBytes( localAttributeLength ) );
// The attribute type
Value.encode( buffer, Asn1StringUtils.asciiStringToByte( attribute.getUpId() ) );
// The values
buffer.put( UniversalTag.SET_TAG );
int localValuesLength = valsLength.get( attributeNumber );
buffer.put( TLV.getBytes( localValuesLength ) );
if ( attribute.size() != 0 )
{
if ( attribute.size() > 0 )
{
for ( org.apache.directory.shared.ldap.entry.Value<?> value : attribute )
{
if ( !value.isBinary() )
{
Value.encode( buffer, value.getString() );
}
else
{
Value.encode( buffer, value.getBytes() );
}
}
}
}
// Go to the next attribute number;
attributeNumber++;
}
}
}
catch ( BufferOverflowException boe )
{
throw new EncoderException( "The PDU buffer size is too small !" );
}
return buffer;
}
/**
* Returns the Search Result Entry string
*
* @return The Search Result Entry string
*/
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append( " Search Result Entry\n" );
sb.append( " entry\n" );
if ( ( entry == null ) || ( entry.size() == 0 ) )
{
sb.append( " No entry\n" );
}
else
{
sb.append( entry );
}
return sb.toString();
}
/**
* @return Returns the currentAttributeValue.
*/
public String getCurrentAttributeValueType()
{
return currentAttributeValue.getId();
}
}