001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.ldap.codec.factory; 021 022import java.util.Iterator; 023import java.util.List; 024 025import org.apache.directory.api.asn1.ber.tlv.BerValue; 026import org.apache.directory.api.asn1.util.Asn1Buffer; 027import org.apache.directory.api.ldap.codec.api.LdapApiService; 028import org.apache.directory.api.ldap.codec.api.LdapCodecConstants; 029import org.apache.directory.api.ldap.model.filter.AndNode; 030import org.apache.directory.api.ldap.model.filter.ApproximateNode; 031import org.apache.directory.api.ldap.model.filter.BranchNode; 032import org.apache.directory.api.ldap.model.filter.EqualityNode; 033import org.apache.directory.api.ldap.model.filter.ExprNode; 034import org.apache.directory.api.ldap.model.filter.ExtensibleNode; 035import org.apache.directory.api.ldap.model.filter.GreaterEqNode; 036import org.apache.directory.api.ldap.model.filter.LessEqNode; 037import org.apache.directory.api.ldap.model.filter.NotNode; 038import org.apache.directory.api.ldap.model.filter.OrNode; 039import org.apache.directory.api.ldap.model.filter.PresenceNode; 040import org.apache.directory.api.ldap.model.filter.SimpleNode; 041import org.apache.directory.api.ldap.model.filter.SubstringNode; 042import org.apache.directory.api.ldap.model.message.Message; 043import org.apache.directory.api.ldap.model.message.SearchRequest; 044import org.apache.directory.api.util.Strings; 045 046/** 047 * The SearchRequest factory. 048 * 049 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 050 */ 051public final class SearchRequestFactory implements Messagefactory 052{ 053 /** The static instance */ 054 public static final SearchRequestFactory INSTANCE = new SearchRequestFactory(); 055 056 private SearchRequestFactory() 057 { 058 // Nothing to do 059 } 060 061 /** 062 * Recursively encode the children of a connector node (AND, OR, NOT) 063 * 064 * @param buffer The buffer where to put the PDU 065 * @param children The children to encode 066 */ 067 private void encodeFilters( Asn1Buffer buffer, Iterator<ExprNode> children ) 068 { 069 if ( children.hasNext() ) 070 { 071 ExprNode child = children.next(); 072 073 // Recurse 074 encodeFilters( buffer, children ); 075 076 // And finally the child, at the right position 077 encodeFilter( buffer, child ); 078 } 079 } 080 081 082 /** 083 * Encode a BranchNode. 084 * <br> 085 * BranchFilter : 086 * <pre> 087 * 0xA1/0xA2/0xA3 LL 088 * filter.encode() ... filter.encode() 089 * </pre> 090 * 091 * @param buffer The buffer where to put the PDU 092 * @param node The Branch filter to encode 093 * @param tag the ASN.1 type 094 */ 095 private void encodeFilter( Asn1Buffer buffer, BranchNode node, byte tag ) 096 { 097 int start = buffer.getPos(); 098 099 // encode each filter 100 List<ExprNode> children = node.getChildren(); 101 102 if ( ( children != null ) && ( !children.isEmpty() ) ) 103 { 104 encodeFilters( buffer, children.iterator() ); 105 } 106 107 // The BranchNode sequence 108 BerValue.encodeSequence( buffer, tag, start ); 109 } 110 111 112 /** 113 * Encode a SimpleNode. 114 * <br> 115 * SimpleFilter : 116 * <pre> 117 * 0xA3/0xA5/0xA6/A8 LL 118 * 0x04 LL attributeDesc 119 * 0x04 LL assertionValue 120 * </pre> 121 * 122 * @param buffer The buffer where to put the PDU 123 * @param node The Simple filter to encode 124 * @param tag the ASN.1 type 125 */ 126 private void encodeFilter( Asn1Buffer buffer, SimpleNode<?> node, byte tag ) 127 { 128 int start = buffer.getPos(); 129 130 // The attribute desc 131 BerValue.encodeOctetString( buffer, node.getValue().getBytes() ); 132 133 // The assertion desc 134 BerValue.encodeOctetString( buffer, node.getAttribute() ); 135 136 // The EqualityNode sequence 137 BerValue.encodeSequence( buffer, tag, start ); 138 } 139 140 141 /** 142 * Encode a PresenceNode. 143 * <br> 144 * PresentFilter : 145 * <pre> 146 * 0x87 L1 present 147 * </pre> 148 * 149 * @param buffer The buffer where to put the PDU 150 * @param node The Presence filter to encode 151 */ 152 private void encodeFilter( Asn1Buffer buffer, PresenceNode node ) 153 { 154 // The PresentFilter Tag 155 BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.PRESENT_FILTER_TAG, 156 Strings.getBytesUtf8( node.getAttribute() ) ); 157 } 158 159 160 /** 161 * Encode a SubstringNode. 162 * <br> 163 * Substrings Filter : 164 * <pre> 165 * 0xA4 LL 166 * 0x04 LL type 167 * 0x30 LL substrings sequence 168 * | 0x80 LL initial 169 * | / [0x81 LL any]* 170 * |/ [0x82 LL final] 171 * +--[0x81 LL any]+ 172 * \ [0x82 LL final] 173 * \ 174 * 0x82 LL final 175 * </pre> 176 * 177 * @param buffer The buffer where to put the PDU 178 * @param node The Substring filter to encode 179 */ 180 private void encodeFilter( Asn1Buffer buffer, SubstringNode node ) 181 { 182 int start = buffer.getPos(); 183 184 // The final 185 if ( node.getFinal() != null ) 186 { 187 BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG, 188 Strings.getBytesUtf8( node.getFinal() ) ); 189 } 190 191 // The any 192 List<String> any = node.getAny(); 193 194 if ( any != null ) 195 { 196 for ( int i = any.size(); i > 0; i-- ) 197 { 198 BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG, 199 Strings.getBytesUtf8( any.get( i - 1 ) ) ); 200 } 201 } 202 203 // The initial 204 if ( node.getInitial() != null ) 205 { 206 BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_INITIAL_TAG, 207 Strings.getBytesUtf8( node.getInitial() ) ); 208 } 209 210 // The Substring sequence 211 BerValue.encodeSequence( buffer, start ); 212 213 // The type 214 BerValue.encodeOctetString( buffer, node.getAttribute() ); 215 216 // The EqualityNode sequence 217 BerValue.encodeSequence( buffer, ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_TAG, start ); 218 } 219 220 221 /** 222 * Encode an ExtensibleNode. 223 * <br> 224 * ExtensibleMatch filter : 225 * <pre> 226 * 0xA9 L1 227 * | 228 * [+--> 0x81 L3 matchingRule] 229 * [+--> 0x82 L4 type] 230 * [+--> 0x83 L5 matchValue] 231 * [+--> 0x01 0x01 dnAttributes] 232 * </pre> 233 * 234 * @param buffer The buffer where to put the PDU 235 * @param node The ExtensibleMatch filter to encode 236 */ 237 private void encodeFilter( Asn1Buffer buffer, ExtensibleNode node ) 238 { 239 int start = buffer.getPos(); 240 241 // The dnAttributes flag, if true only 242 if ( node.hasDnAttributes() ) 243 { 244 BerValue.encodeBoolean( buffer, ( byte ) LdapCodecConstants.DN_ATTRIBUTES_FILTER_TAG, true ); 245 } 246 247 // The matching value 248 if ( node.getValue() != null ) 249 { 250 BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.MATCH_VALUE_TAG, 251 node.getValue().getBytes() ); 252 } 253 254 // The type 255 if ( node.getAttribute() != null ) 256 { 257 BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.MATCHING_RULE_TYPE_TAG, 258 Strings.getBytesUtf8( node.getAttribute() ) ); 259 } 260 261 // The matching rule 262 if ( node.getMatchingRuleId() != null ) 263 { 264 BerValue.encodeOctetString( buffer, ( byte ) LdapCodecConstants.MATCHING_RULE_ID_TAG, 265 Strings.getBytesUtf8( node.getMatchingRuleId() ) ); 266 } 267 268 // The EqualityNode sequence 269 BerValue.encodeSequence( buffer, ( byte ) LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG, start ); 270 } 271 272 273 /** 274 * Encode a Search Filter 275 * 276 * @param buffer The buffer where to put the PDU 277 * @param node The top filter 278 */ 279 private void encodeFilter( Asn1Buffer buffer, ExprNode node ) 280 { 281 switch ( node.getClass().getSimpleName() ) 282 { 283 case "AndNode" : 284 encodeFilter( buffer, ( AndNode ) node, ( byte ) LdapCodecConstants.AND_FILTER_TAG ); 285 break; 286 287 case "ApproximateNode" : 288 encodeFilter( buffer, ( ApproximateNode<?> ) node, ( byte ) LdapCodecConstants.APPROX_MATCH_FILTER_TAG ); 289 break; 290 291 case "EqualityNode" : 292 encodeFilter( buffer, ( EqualityNode<?> ) node, ( byte ) LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG ); 293 break; 294 295 case "ExtensibleNode" : 296 encodeFilter( buffer, ( ExtensibleNode ) node ); 297 break; 298 299 case "GreaterEqNode" : 300 encodeFilter( buffer, ( GreaterEqNode<?> ) node, ( byte ) LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG ); 301 break; 302 303 case "LessEqNode" : 304 encodeFilter( buffer, ( LessEqNode<?> ) node, ( byte ) LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG ); 305 break; 306 307 case "NotNode" : 308 encodeFilter( buffer, ( NotNode ) node, ( byte ) LdapCodecConstants.NOT_FILTER_TAG ); 309 break; 310 311 case "OrNode" : 312 encodeFilter( buffer, ( OrNode ) node, ( byte ) LdapCodecConstants.OR_FILTER_TAG ); 313 break; 314 315 case "PresenceNode" : 316 encodeFilter( buffer, ( PresenceNode ) node ); 317 break; 318 319 case "SubstringNode" : 320 encodeFilter( buffer, ( SubstringNode ) node ); 321 break; 322 323 default: 324 break; 325 } 326 } 327 328 /** 329 * Encode the SearchRequest message to a PDU. 330 * <br> 331 * SearchRequest : 332 * <pre> 333 * 0x63 LL 334 * 0x04 LL baseObject 335 * 0x0A 01 scope 336 * 0x0A 01 derefAliases 337 * 0x02 0N sizeLimit 338 * 0x02 0N timeLimit 339 * 0x01 0x01 typesOnly 340 * filter.encode() 341 * 0x30 LL attributeDescriptionList 342 * 0x04 LL attributeDescription 343 * ... 344 * 0x04 LL attributeDescription 345 * </pre> 346 * 347 * @param codec The LdapApiService instance 348 * @param buffer The buffer where to put the PDU 349 * @param message the ModifyRequest to encode 350 */ 351 @Override 352 public void encodeReverse( LdapApiService codec, Asn1Buffer buffer, Message message ) 353 { 354 int start = buffer.getPos(); 355 SearchRequest searchRequest = ( SearchRequest ) message; 356 357 // The attributes, if any 358 List<String> attributes = searchRequest.getAttributes(); 359 360 if ( ( attributes != null ) && ( !attributes.isEmpty() ) ) 361 { 362 for ( int i = attributes.size(); i > 0; i-- ) 363 { 364 BerValue.encodeOctetString( buffer, attributes.get( i - 1 ) ); 365 } 366 } 367 368 // The attributes sequence 369 BerValue.encodeSequence( buffer, start ); 370 371 // The filter 372 encodeFilter( buffer, searchRequest.getFilter() ); 373 374 // The typesOnly 375 BerValue.encodeBoolean( buffer, searchRequest.getTypesOnly() ); 376 377 // The timeLimit 378 BerValue.encodeInteger( buffer, searchRequest.getTimeLimit() ); 379 380 // The sizeLimit 381 BerValue.encodeInteger( buffer, searchRequest.getSizeLimit() ); 382 383 // The derefAliases 384 BerValue.encodeEnumerated( buffer, searchRequest.getDerefAliases().getValue() ); 385 386 // The scope 387 BerValue.encodeEnumerated( buffer, searchRequest.getScope().getScope() ); 388 389 // The base object 390 BerValue.encodeOctetString( buffer, Strings.getBytesUtf8( searchRequest.getBase().getName() ) ); 391 392 // The SearchRequest tag 393 BerValue.encodeSequence( buffer, LdapCodecConstants.SEARCH_REQUEST_TAG, start ); 394 } 395}