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   *    http://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.LdapConstants;
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<String>( 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      // ~ Methods
81      // ------------------------------------------------------------------------------------
82  
83      /**
84       * The constructor. We will create the 'any' subsring arraylist with only
85       * one element.
86       */
87      public SubstringFilter( int tlvId )
88      {
89          super( tlvId );
90      }
91  
92  
93      /**
94       * The constructor. We will create the 'any' subsring arraylist with only
95       * one element.
96       */
97      public SubstringFilter()
98      {
99          super();
100     }
101 
102 
103     /**
104      * Get the internal substrings
105      * 
106      * @return Returns the anySubstrings.
107      */
108     public List<String> getAnySubstrings()
109     {
110         return anySubstrings;
111     }
112 
113 
114     /**
115      * Add a internal substring
116      * 
117      * @param any The anySubstrings to set.
118      */
119     public void addAnySubstrings( String any )
120     {
121         this.anySubstrings.add( any );
122     }
123 
124 
125     /**
126      * Get the final substring
127      * 
128      * @return Returns the finalSubstrings.
129      */
130     public String getFinalSubstrings()
131     {
132         return finalSubstrings;
133     }
134 
135 
136     /**
137      * Set the final substring
138      * 
139      * @param finalSubstrings The finalSubstrings to set.
140      */
141     public void setFinalSubstrings( String finalSubstrings )
142     {
143         this.finalSubstrings = finalSubstrings;
144     }
145 
146 
147     /**
148      * Get the initial substring
149      * 
150      * @return Returns the initialSubstrings.
151      */
152     public String getInitialSubstrings()
153     {
154         return initialSubstrings;
155     }
156 
157 
158     /**
159      * Set the initial substring
160      * 
161      * @param initialSubstrings The initialSubstrings to set.
162      */
163     public void setInitialSubstrings( String initialSubstrings )
164     {
165         this.initialSubstrings = initialSubstrings;
166     }
167 
168 
169     /**
170      * Get the attribute
171      * 
172      * @return Returns the type.
173      */
174     public String getType()
175     {
176         return type;
177     }
178 
179 
180     /**
181      * Set the attribute to match
182      * 
183      * @param type The type to set.
184      */
185     public void setType( String type )
186     {
187         this.type = type;
188     }
189 
190 
191     /**
192      * @return Returns the substringsLength.
193      */
194     public int getSubstringsLength()
195     {
196         return substringsLength;
197     }
198 
199 
200     /**
201      * @param substringsLength The substringsLength to set.
202      */
203     public void setSubstringsLength( int substringsLength )
204     {
205         this.substringsLength = substringsLength;
206     }
207 
208 
209     /**
210      * Compute the SubstringFilter length 
211      * 
212      * SubstringFilter : 
213      * 0xA4 L1 
214      *   | 
215      *   +--> 0x04 L2 type 
216      *   +--> 0x30 L3 
217      *          | 
218      *         [+--> 0x80 L4 initial] 
219      *         [+--> 0x81 L5-1 any] 
220      *         [+--> 0x81 L5-2 any] 
221      *         [+--> ... 
222      *         [+--> 0x81 L5-i any] 
223      *         [+--> ... 
224      *         [+--> 0x81 L5-n any] 
225      *         [+--> 0x82 L6 final]
226      */
227     public int computeLength()
228     {
229         // The type
230         int typeLength = Strings.getBytesUtf8( type ).length;
231 
232         substringsFilterLength = 1 + TLV.getNbBytes( typeLength ) + typeLength;
233         substringsFilterSequenceLength = 0;
234 
235         if ( initialSubstrings != null )
236         {
237             int initialLength = Strings.getBytesUtf8( initialSubstrings ).length;
238             substringsFilterSequenceLength += 1 + TLV.getNbBytes( initialLength )
239                 + initialLength;
240         }
241 
242         if ( anySubstrings != null )
243         {
244             for ( String any : anySubstrings )
245             {
246                 int anyLength = Strings.getBytesUtf8( any ).length;
247                 substringsFilterSequenceLength += 1 + TLV.getNbBytes( anyLength ) + anyLength;
248             }
249         }
250 
251         if ( finalSubstrings != null )
252         {
253             int finalLength = Strings.getBytesUtf8( finalSubstrings ).length;
254             substringsFilterSequenceLength += 1 + TLV.getNbBytes( finalLength )
255                 + finalLength;
256         }
257 
258         substringsFilterLength += 1 + TLV.getNbBytes( substringsFilterSequenceLength )
259             + substringsFilterSequenceLength;
260 
261         return 1 + TLV.getNbBytes( substringsFilterLength ) + substringsFilterLength;
262     }
263 
264 
265     /**
266      * Encode the Substrings Filter to a PDU. 
267      * 
268      * Substrings Filter :
269      * 
270      * 0xA4 LL 
271      * 0x30 LL substringsFilter
272      *   0x04 LL type
273      *   0x30 LL substrings sequence
274      *    |  0x80 LL initial
275      *    | /  [0x81 LL any]* 
276      *    |/   [0x82 LL final]
277      *    +--[0x81 LL any]+
278      *     \   [0x82 LL final]
279      *      \
280      *       0x82 LL final
281      * 
282      * @param buffer The buffer where to put the PDU
283      * @return The PDU.
284      */
285     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
286     {
287         if ( buffer == null )
288         {
289             throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
290         }
291 
292         try
293         {
294             // The SubstringFilter Tag
295             buffer.put( ( byte ) LdapConstants.SUBSTRINGS_FILTER_TAG );
296             buffer.put( TLV.getBytes( substringsFilterLength ) );
297 
298             // The type
299             BerValue.encode( buffer, type.getBytes() );
300 
301             // The SubstringSequenceFilter Tag
302             buffer.put( UniversalTag.SEQUENCE.getValue() );
303             buffer.put( TLV.getBytes( substringsFilterSequenceLength ) );
304 
305             if ( ( initialSubstrings == null ) && ( ( anySubstrings == null ) || ( anySubstrings.size() == 0 ) )
306                 && ( finalSubstrings == null ) )
307             {
308                 throw new EncoderException( I18n.err( I18n.ERR_04058 ) );
309             }
310 
311             // The initial substring
312             if ( initialSubstrings != null )
313             {
314                 byte[] initialBytes = Strings.getBytesUtf8( initialSubstrings );
315                 buffer.put( ( byte ) LdapConstants.SUBSTRINGS_FILTER_INITIAL_TAG );
316                 buffer.put( TLV.getBytes( initialBytes.length ) );
317                 buffer.put( initialBytes );
318             }
319 
320             // The any substrings
321             if ( anySubstrings != null )
322             {
323                 for ( String any : anySubstrings )
324                 {
325                     byte[] anyBytes = Strings.getBytesUtf8( any );
326                     buffer.put( ( byte ) LdapConstants.SUBSTRINGS_FILTER_ANY_TAG );
327                     buffer.put( TLV.getBytes( anyBytes.length ) );
328                     buffer.put( anyBytes );
329                 }
330             }
331 
332             // The final substring
333             if ( finalSubstrings != null )
334             {
335                 byte[] finalBytes = Strings.getBytesUtf8( finalSubstrings );
336                 buffer.put( ( byte ) LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG );
337                 buffer.put( TLV.getBytes( finalBytes.length ) );
338                 buffer.put( finalBytes );
339             }
340         }
341         catch ( BufferOverflowException boe )
342         {
343             throw new EncoderException( I18n.err( I18n.ERR_04005 ) );
344         }
345 
346         return buffer;
347     }
348 
349 
350     /**
351      * Return a string compliant with RFC 2254 representing a Substring filter
352      * 
353      * @return The substring filter string
354      */
355     public String toString()
356     {
357 
358         StringBuffer sb = new StringBuffer();
359 
360         if ( initialSubstrings != null )
361         {
362             sb.append( initialSubstrings );
363         }
364 
365         sb.append( '*' );
366 
367         if ( anySubstrings != null )
368         {
369             for ( String any : anySubstrings )
370             {
371                 sb.append( any ).append( '*' );
372             }
373         }
374 
375         if ( finalSubstrings != null )
376         {
377             sb.append( finalSubstrings );
378         }
379 
380         return sb.toString();
381     }
382 }