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.search;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import org.apache.directory.api.asn1.EncoderException;
29  import org.apache.directory.api.asn1.ber.tlv.BerValue;
30  import org.apache.directory.api.asn1.ber.tlv.TLV;
31  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
32  import org.apache.directory.api.i18n.I18n;
33  import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
34  import org.apache.directory.api.util.Strings;
35  
36  
37  /**
38   * A Object that stores the substring filter. 
39   * 
40   * A substring filter follow this
41   * grammar : 
42   * 
43   * substring = attr "=" ( ([initial] any [final] | 
44   *                        (initial [any] [final) | 
45   *                        ([initial] [any] final) ) 
46   *                       
47   * initial = value 
48   * any = "*" *(value "*")
49   * final = value
50   * 
51   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
52   */
53  public class SubstringFilter extends Filter
54  {
55      /** The substring filter type (an attributeDescription) */
56      private String type;
57  
58      /**
59       * This member is used to control the length of the three parts of the
60       * substring filter
61       */
62      private int substringsLength;
63  
64      /** The initial filter */
65      private String initialSubstrings;
66  
67      /** The any filter. It's a list of LdapString */
68      private List<String> anySubstrings = new ArrayList<>( 1 );
69  
70      /** The final filter */
71      private String finalSubstrings;
72  
73      /** Temporary storage for substringsFilter length */
74      private int substringsFilterLength;
75  
76      /** Temporary storage for substringsFilter sequence length */
77      private int substringsFilterSequenceLength;
78  
79  
80      /**
81       * The constructor. We will create the 'any' subsring arraylist with only
82       * one element.
83       * 
84       * @param tlvId The TLV identifier
85       */
86      public SubstringFilter( int tlvId )
87      {
88          super( tlvId );
89      }
90  
91  
92      /**
93       * The constructor. We will create the 'any' subsring arraylist with only
94       * one element.
95       */
96      public SubstringFilter()
97      {
98          super();
99      }
100 
101 
102     /**
103      * Get the internal substrings
104      * 
105      * @return Returns the anySubstrings.
106      */
107     public List<String> getAnySubstrings()
108     {
109         return anySubstrings;
110     }
111 
112 
113     /**
114      * Add a internal substring
115      * 
116      * @param any The anySubstrings to set.
117      */
118     public void addAnySubstrings( String any )
119     {
120         this.anySubstrings.add( any );
121     }
122 
123 
124     /**
125      * Get the final substring
126      * 
127      * @return Returns the finalSubstrings.
128      */
129     public String getFinalSubstrings()
130     {
131         return finalSubstrings;
132     }
133 
134 
135     /**
136      * Set the final substring
137      * 
138      * @param finalSubstrings The finalSubstrings to set.
139      */
140     public void setFinalSubstrings( String finalSubstrings )
141     {
142         this.finalSubstrings = finalSubstrings;
143     }
144 
145 
146     /**
147      * Get the initial substring
148      * 
149      * @return Returns the initialSubstrings.
150      */
151     public String getInitialSubstrings()
152     {
153         return initialSubstrings;
154     }
155 
156 
157     /**
158      * Set the initial substring
159      * 
160      * @param initialSubstrings The initialSubstrings to set.
161      */
162     public void setInitialSubstrings( String initialSubstrings )
163     {
164         this.initialSubstrings = initialSubstrings;
165     }
166 
167 
168     /**
169      * Get the attribute
170      * 
171      * @return Returns the type.
172      */
173     public String getType()
174     {
175         return type;
176     }
177 
178 
179     /**
180      * Set the attribute to match
181      * 
182      * @param type The type to set.
183      */
184     public void setType( String type )
185     {
186         this.type = type;
187     }
188 
189 
190     /**
191      * @return Returns the substringsLength.
192      */
193     public int getSubstringsLength()
194     {
195         return substringsLength;
196     }
197 
198 
199     /**
200      * @param substringsLength The substringsLength to set.
201      */
202     public void setSubstringsLength( int substringsLength )
203     {
204         this.substringsLength = substringsLength;
205     }
206 
207 
208     /**
209      * Compute the SubstringFilter length 
210      * <br>
211      * SubstringFilter :
212      * <pre> 
213      * 0xA4 L1 
214      *   | 
215      *   +--&gt; 0x04 L2 type 
216      *   +--&gt; 0x30 L3 
217      *          | 
218      *         [+--&gt; 0x80 L4 initial] 
219      *         [+--&gt; 0x81 L5-1 any] 
220      *         [+--&gt; 0x81 L5-2 any] 
221      *         [+--&gt; ... 
222      *         [+--&gt; 0x81 L5-i any] 
223      *         [+--&gt; ... 
224      *         [+--&gt; 0x81 L5-n any] 
225      *         [+--&gt; 0x82 L6 final]
226      * </pre>
227      * 
228      * @return The encoded length
229      */
230     @Override
231     public int computeLength()
232     {
233         // The type
234         int typeLength = Strings.getBytesUtf8( type ).length;
235 
236         substringsFilterLength = 1 + TLV.getNbBytes( typeLength ) + typeLength;
237         substringsFilterSequenceLength = 0;
238 
239         if ( initialSubstrings != null )
240         {
241             int initialLength = Strings.getBytesUtf8( initialSubstrings ).length;
242             substringsFilterSequenceLength += 1 + TLV.getNbBytes( initialLength )
243                 + initialLength;
244         }
245 
246         if ( anySubstrings != null )
247         {
248             for ( String any : anySubstrings )
249             {
250                 int anyLength = Strings.getBytesUtf8( any ).length;
251                 substringsFilterSequenceLength += 1 + TLV.getNbBytes( anyLength ) + anyLength;
252             }
253         }
254 
255         if ( finalSubstrings != null )
256         {
257             int finalLength = Strings.getBytesUtf8( finalSubstrings ).length;
258             substringsFilterSequenceLength += 1 + TLV.getNbBytes( finalLength )
259                 + finalLength;
260         }
261 
262         substringsFilterLength += 1 + TLV.getNbBytes( substringsFilterSequenceLength )
263             + substringsFilterSequenceLength;
264 
265         return 1 + TLV.getNbBytes( substringsFilterLength ) + substringsFilterLength;
266     }
267 
268 
269     /**
270      * Encode the Substrings Filter to a PDU. 
271      * <br>
272      * Substrings Filter :
273      * <pre>
274      * 0xA4 LL 
275      * 0x30 LL substringsFilter
276      *   0x04 LL type
277      *   0x30 LL substrings sequence
278      *    |  0x80 LL initial
279      *    | /  [0x81 LL any]* 
280      *    |/   [0x82 LL final]
281      *    +--[0x81 LL any]+
282      *     \   [0x82 LL final]
283      *      \
284      *       0x82 LL final
285      * </pre>
286      * 
287      * @param buffer The buffer where to put the PDU
288      * @return The PDU.
289      */
290     @Override
291     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
292     {
293         if ( buffer == null )
294         {
295             throw new EncoderException( I18n.err( I18n.ERR_08000_CANNOT_PUT_A_PDU_IN_NULL_BUFFER ) );
296         }
297 
298         try
299         {
300             // The SubstringFilter Tag
301             buffer.put( ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_TAG );
302             buffer.put( TLV.getBytes( substringsFilterLength ) );
303 
304             // The type
305             BerValue.encode( buffer, Strings.getBytesUtf8( type ) );
306 
307             // The SubstringSequenceFilter Tag
308             buffer.put( UniversalTag.SEQUENCE.getValue() );
309             buffer.put( TLV.getBytes( substringsFilterSequenceLength ) );
310 
311             if ( ( initialSubstrings == null ) && ( ( anySubstrings == null ) || anySubstrings.isEmpty() )
312                 && ( finalSubstrings == null ) )
313             {
314                 throw new EncoderException( I18n.err( I18n.ERR_05502_NULL_INITIAL_ANY_OR_FINAL_SUBSTRING ) );
315             }
316 
317             // The initial substring
318             if ( initialSubstrings != null )
319             {
320                 byte[] initialBytes = Strings.getBytesUtf8( initialSubstrings );
321                 buffer.put( ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_INITIAL_TAG );
322                 buffer.put( TLV.getBytes( initialBytes.length ) );
323                 buffer.put( initialBytes );
324             }
325 
326             // The any substrings
327             if ( anySubstrings != null )
328             {
329                 for ( String any : anySubstrings )
330                 {
331                     byte[] anyBytes = Strings.getBytesUtf8( any );
332                     buffer.put( ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG );
333                     buffer.put( TLV.getBytes( anyBytes.length ) );
334                     buffer.put( anyBytes );
335                 }
336             }
337 
338             // The final substring
339             if ( finalSubstrings != null )
340             {
341                 byte[] finalBytes = Strings.getBytesUtf8( finalSubstrings );
342                 buffer.put( ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG );
343                 buffer.put( TLV.getBytes( finalBytes.length ) );
344                 buffer.put( finalBytes );
345             }
346         }
347         catch ( BufferOverflowException boe )
348         {
349             throw new EncoderException( I18n.err( I18n.ERR_08212_PDU_BUFFER_TOO_SMALL ), boe );
350         }
351 
352         return buffer;
353     }
354 
355 
356     /**
357      * Return a string compliant with RFC 2254 representing a Substring filter
358      * 
359      * @return The substring filter string
360      */
361     @Override
362     public String toString()
363     {
364 
365         StringBuilder sb = new StringBuilder();
366 
367         if ( initialSubstrings != null )
368         {
369             sb.append( initialSubstrings );
370         }
371 
372         sb.append( '*' );
373 
374         if ( anySubstrings != null )
375         {
376             for ( String any : anySubstrings )
377             {
378                 sb.append( any ).append( '*' );
379             }
380         }
381 
382         if ( finalSubstrings != null )
383         {
384             sb.append( finalSubstrings );
385         }
386 
387         return sb.toString();
388     }
389 }