blob: 5252cf07a06cfe18e3bb0013d7155ecad92fbe97 [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
*
* https://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.api.ldap.codec.factory;
import java.util.Iterator;
import java.util.List;
import org.apache.directory.api.asn1.ber.tlv.BerValue;
import org.apache.directory.api.asn1.util.Asn1Buffer;
import org.apache.directory.api.ldap.codec.api.LdapApiService;
import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
import org.apache.directory.api.ldap.model.filter.AndNode;
import org.apache.directory.api.ldap.model.filter.ApproximateNode;
import org.apache.directory.api.ldap.model.filter.BranchNode;
import org.apache.directory.api.ldap.model.filter.EqualityNode;
import org.apache.directory.api.ldap.model.filter.ExprNode;
import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
import org.apache.directory.api.ldap.model.filter.LessEqNode;
import org.apache.directory.api.ldap.model.filter.NotNode;
import org.apache.directory.api.ldap.model.filter.OrNode;
import org.apache.directory.api.ldap.model.filter.PresenceNode;
import org.apache.directory.api.ldap.model.filter.SimpleNode;
import org.apache.directory.api.ldap.model.filter.SubstringNode;
import org.apache.directory.api.ldap.model.message.Message;
import org.apache.directory.api.ldap.model.message.SearchRequest;
import org.apache.directory.api.util.Strings;
/**
* The SearchRequest factory.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public final class SearchRequestFactory implements Messagefactory
{
/** The static instance */
public static final SearchRequestFactory INSTANCE = new SearchRequestFactory();
private SearchRequestFactory()
{
// Nothing to do
}
/**
* Recursively encode the children of a connector node (AND, OR, NOT)
*
* @param buffer The buffer where to put the PDU
* @param children The children to encode
*/
private void encodeFilters( Asn1Buffer buffer, Iterator<ExprNode> children )
{
if ( children.hasNext() )
{
ExprNode child = children.next();
// Recurse
encodeFilters( buffer, children );
// And finally the child, at the right position
encodeFilter( buffer, child );
}
}
/**
* Encode a BranchNode.
* <br>
* BranchFilter :
* <pre>
* 0xA1/0xA2/0xA3 LL
* filter.encode() ... filter.encode()
* </pre>
*
* @param buffer The buffer where to put the PDU
* @param node The Branch filter to encode
* @param tag the ASN.1 type
*/
private void encodeFilter( Asn1Buffer buffer, BranchNode node, byte tag )
{
int start = buffer.getPos();
// encode each filter
List<ExprNode> children = node.getChildren();
if ( ( children != null ) && ( !children.isEmpty() ) )
{
encodeFilters( buffer, children.iterator() );
}
// The BranchNode sequence
BerValue.encodeSequence( buffer, tag, start );
}
/**
* Encode a SimpleNode.
* <br>
* SimpleFilter :
* <pre>
* 0xA3/0xA5/0xA6/A8 LL
* 0x04 LL attributeDesc
* 0x04 LL assertionValue
* </pre>
*
* @param buffer The buffer where to put the PDU
* @param node The Simple filter to encode
* @param tag the ASN.1 type
*/
private void encodeFilter( Asn1Buffer buffer, SimpleNode<?> node, byte tag )
{
int start = buffer.getPos();
// The attribute desc
BerValue.encodeOctetString( buffer, node.getValue().getBytes() );
// The assertion desc
BerValue.encodeOctetString( buffer, node.getAttribute() );
// The EqualityNode sequence
BerValue.encodeSequence( buffer, tag, start );
}
/**
* Encode a PresenceNode.
* <br>
* PresentFilter :
* <pre>
* 0x87 L1 present
* </pre>
*
* @param buffer The buffer where to put the PDU
* @param node The Presence filter to encode
*/
private void encodeFilter( Asn1Buffer buffer, PresenceNode node )
{
// The PresentFilter Tag
BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.PRESENT_FILTER_TAG,
Strings.getBytesUtf8( node.getAttribute() ) );
}
/**
* Encode a SubstringNode.
* <br>
* Substrings Filter :
* <pre>
* 0xA4 LL
* 0x04 LL type
* 0x30 LL substrings sequence
* | 0x80 LL initial
* | / [0x81 LL any]*
* |/ [0x82 LL final]
* +--[0x81 LL any]+
* \ [0x82 LL final]
* \
* 0x82 LL final
* </pre>
*
* @param buffer The buffer where to put the PDU
* @param node The Substring filter to encode
*/
private void encodeFilter( Asn1Buffer buffer, SubstringNode node )
{
int start = buffer.getPos();
// The final
if ( node.getFinal() != null )
{
BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG,
Strings.getBytesUtf8( node.getFinal() ) );
}
// The any
List<String> any = node.getAny();
if ( any != null )
{
for ( int i = any.size(); i > 0; i-- )
{
BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG,
Strings.getBytesUtf8( any.get( i - 1 ) ) );
}
}
// The initial
if ( node.getInitial() != null )
{
BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_INITIAL_TAG,
Strings.getBytesUtf8( node.getInitial() ) );
}
// The Substring sequence
BerValue.encodeSequence( buffer, start );
// The type
BerValue.encodeOctetString( buffer, node.getAttribute() );
// The EqualityNode sequence
BerValue.encodeSequence( buffer, ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_TAG, start );
}
/**
* Encode an ExtensibleNode.
* <br>
* ExtensibleMatch filter :
* <pre>
* 0xA9 L1
* |
* [+--&gt; 0x81 L3 matchingRule]
* [+--&gt; 0x82 L4 type]
* [+--&gt; 0x83 L5 matchValue]
* [+--&gt; 0x01 0x01 dnAttributes]
* </pre>
*
* @param buffer The buffer where to put the PDU
* @param node The ExtensibleMatch filter to encode
*/
private void encodeFilter( Asn1Buffer buffer, ExtensibleNode node )
{
int start = buffer.getPos();
// The dnAttributes flag, if true only
if ( node.hasDnAttributes() )
{
BerValue.encodeBoolean( buffer, ( byte ) LdapCodecConstants.DN_ATTRIBUTES_FILTER_TAG, true );
}
// The matching value
if ( node.getValue() != null )
{
BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.MATCH_VALUE_TAG,
node.getValue().getBytes() );
}
// The type
if ( node.getAttribute() != null )
{
BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.MATCHING_RULE_TYPE_TAG,
Strings.getBytesUtf8( node.getAttribute() ) );
}
// The matching rule
if ( node.getMatchingRuleId() != null )
{
BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.MATCHING_RULE_ID_TAG,
Strings.getBytesUtf8( node.getMatchingRuleId() ) );
}
// The EqualityNode sequence
BerValue.encodeSequence( buffer, ( byte ) LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG, start );
}
/**
* Encode a Search Filter
*
* @param buffer The buffer where to put the PDU
* @param node The top filter
*/
private void encodeFilter( Asn1Buffer buffer, ExprNode node )
{
switch ( node.getClass().getSimpleName() )
{
case "AndNode" :
encodeFilter( buffer, ( AndNode ) node, ( byte ) LdapCodecConstants.AND_FILTER_TAG );
break;
case "ApproximateNode" :
encodeFilter( buffer, ( ApproximateNode<?> ) node, ( byte ) LdapCodecConstants.APPROX_MATCH_FILTER_TAG );
break;
case "EqualityNode" :
encodeFilter( buffer, ( EqualityNode<?> ) node, ( byte ) LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG );
break;
case "ExtensibleNode" :
encodeFilter( buffer, ( ExtensibleNode ) node );
break;
case "GreaterEqNode" :
encodeFilter( buffer, ( GreaterEqNode<?> ) node, ( byte ) LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG );
break;
case "LessEqNode" :
encodeFilter( buffer, ( LessEqNode<?> ) node, ( byte ) LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG );
break;
case "NotNode" :
encodeFilter( buffer, ( NotNode ) node, ( byte ) LdapCodecConstants.NOT_FILTER_TAG );
break;
case "OrNode" :
encodeFilter( buffer, ( OrNode ) node, ( byte ) LdapCodecConstants.OR_FILTER_TAG );
break;
case "PresenceNode" :
encodeFilter( buffer, ( PresenceNode ) node );
break;
case "SubstringNode" :
encodeFilter( buffer, ( SubstringNode ) node );
break;
default:
break;
}
}
/**
* Encode the SearchRequest message to a PDU.
* <br>
* SearchRequest :
* <pre>
* 0x63 LL
* 0x04 LL baseObject
* 0x0A 01 scope
* 0x0A 01 derefAliases
* 0x02 0N sizeLimit
* 0x02 0N timeLimit
* 0x01 0x01 typesOnly
* filter.encode()
* 0x30 LL attributeDescriptionList
* 0x04 LL attributeDescription
* ...
* 0x04 LL attributeDescription
* </pre>
*
* @param codec The LdapApiService instance
* @param buffer The buffer where to put the PDU
* @param message the ModifyRequest to encode
*/
@Override
public void encodeReverse( LdapApiService codec, Asn1Buffer buffer, Message message )
{
int start = buffer.getPos();
SearchRequest searchRequest = ( SearchRequest ) message;
// The attributes, if any
List<String> attributes = searchRequest.getAttributes();
if ( ( attributes != null ) && ( !attributes.isEmpty() ) )
{
for ( int i = attributes.size(); i > 0; i-- )
{
BerValue.encodeOctetString( buffer, attributes.get( i - 1 ) );
}
}
// The attributes sequence
BerValue.encodeSequence( buffer, start );
// The filter
encodeFilter( buffer, searchRequest.getFilter() );
// The typesOnly
BerValue.encodeBoolean( buffer, searchRequest.getTypesOnly() );
// The timeLimit
BerValue.encodeInteger( buffer, searchRequest.getTimeLimit() );
// The sizeLimit
BerValue.encodeInteger( buffer, searchRequest.getSizeLimit() );
// The derefAliases
BerValue.encodeEnumerated( buffer, searchRequest.getDerefAliases().getValue() );
// The scope
BerValue.encodeEnumerated( buffer, searchRequest.getScope().getScope() );
// The base object
BerValue.encodeOctetString( buffer, Strings.getBytesUtf8( searchRequest.getBase().getName() ) );
// The SearchRequest tag
BerValue.encodeSequence( buffer, LdapCodecConstants.SEARCH_REQUEST_TAG, start );
}
}