View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.api.ldap.codec.factory;
21  
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import org.apache.directory.api.asn1.ber.tlv.BerValue;
26  import org.apache.directory.api.asn1.util.Asn1Buffer;
27  import org.apache.directory.api.ldap.codec.api.LdapApiService;
28  import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
29  import org.apache.directory.api.ldap.model.filter.AndNode;
30  import org.apache.directory.api.ldap.model.filter.ApproximateNode;
31  import org.apache.directory.api.ldap.model.filter.BranchNode;
32  import org.apache.directory.api.ldap.model.filter.EqualityNode;
33  import org.apache.directory.api.ldap.model.filter.ExprNode;
34  import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
35  import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
36  import org.apache.directory.api.ldap.model.filter.LessEqNode;
37  import org.apache.directory.api.ldap.model.filter.NotNode;
38  import org.apache.directory.api.ldap.model.filter.OrNode;
39  import org.apache.directory.api.ldap.model.filter.PresenceNode;
40  import org.apache.directory.api.ldap.model.filter.SimpleNode;
41  import org.apache.directory.api.ldap.model.filter.SubstringNode;
42  import org.apache.directory.api.ldap.model.message.Message;
43  import org.apache.directory.api.ldap.model.message.SearchRequest;
44  import org.apache.directory.api.util.Strings;
45  
46  /**
47   * The SearchRequest factory.
48   *
49   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
50   */
51  public final class SearchRequestFactory implements Messagefactory
52  {
53      /** The static instance */
54      public static final SearchRequestFactory INSTANCE = new SearchRequestFactory();
55  
56      private SearchRequestFactory()
57      {
58          // Nothing to do
59      }
60  
61      /**
62       * Recursively encode the children of a connector node (AND, OR, NOT)
63       *
64       * @param buffer The buffer where to put the PDU
65       * @param children The children to encode
66       */
67      private void encodeFilters( Asn1Buffer buffer, Iterator<ExprNode> children )
68      {
69          if ( children.hasNext() )
70          {
71              ExprNode child = children.next();
72  
73              // Recurse
74              encodeFilters( buffer, children );
75  
76              // And finally the child, at the right position
77              encodeFilter( buffer, child );
78          }
79      }
80  
81  
82      /**
83       * Encode a BranchNode.
84       * <br>
85       * BranchFilter :
86       * <pre>
87       * 0xA1/0xA2/0xA3 LL
88       *  filter.encode() ... filter.encode()
89       * </pre>
90       *
91       * @param buffer The buffer where to put the PDU
92       * @param node The Branch filter to encode
93       * @param tag the ASN.1 type
94       */
95      private void encodeFilter( Asn1Buffer buffer, BranchNode node, byte tag )
96      {
97          int start = buffer.getPos();
98  
99          // 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      *  [+--&gt; 0x81 L3 matchingRule]
229      *  [+--&gt; 0x82 L4 type]
230      *  [+--&gt; 0x83 L5 matchValue]
231      *  [+--&gt; 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 }