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     */
020    package org.apache.directory.shared.ldap.codec.search;
021    
022    
023    import java.nio.BufferOverflowException;
024    import java.nio.ByteBuffer;
025    import java.util.ArrayList;
026    import java.util.List;
027    
028    import org.apache.directory.shared.asn1.ber.tlv.TLV;
029    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
030    import org.apache.directory.shared.asn1.ber.tlv.Value;
031    import org.apache.directory.shared.asn1.codec.EncoderException;
032    import org.apache.directory.shared.i18n.I18n;
033    import org.apache.directory.shared.ldap.codec.LdapConstants;
034    import org.apache.directory.shared.ldap.util.StringTools;
035    
036    
037    /**
038     * A Object that stores the substring filter. 
039     * 
040     * A substring filter follow this
041     * grammar : 
042     * 
043     * substring = attr "=" ( ([initial] any [final] | 
044     *                        (initial [any] [final) | 
045     *                        ([initial] [any] final) ) 
046     *                       
047     * initial = value 
048     * any = "*" *(value "*")
049     * final = value
050     * 
051     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
052     * @version $Rev: 912399 $, $Date: 2010-02-21 21:52:31 +0100 (Sun, 21 Feb 2010) $, 
053     */
054    public class SubstringFilter extends Filter
055    {
056        // ~ Instance fields
057        // ----------------------------------------------------------------------------
058    
059        /** The substring filter type (an attributeDescription) */
060        private String type;
061        
062        /** The type length */
063        private int typeLength;
064    
065        /**
066         * This member is used to control the length of the three parts of the
067         * substring filter
068         */
069        private int substringsLength;
070    
071        /** The initial filter */
072        private String initialSubstrings;
073    
074        /** The any filter. It's a list of LdapString */
075        private List<String> anySubstrings = new ArrayList<String>( 1 );
076    
077        /** The final filter */
078        private String finalSubstrings;
079    
080        /** Temporary storage for substringsFilter length */
081        private int substringsFilterLength;
082    
083        /** Temporary storage for substringsFilter sequence length */
084        private int substringsFilterSequenceLength;
085    
086    
087        // ~ Methods
088        // ------------------------------------------------------------------------------------
089    
090        /**
091         * The constructor. We will create the 'any' subsring arraylist with only
092         * one element.
093         */
094        public SubstringFilter( int tlvId )
095        {
096            super( tlvId );
097        }
098        
099        
100        /**
101         * The constructor. We will create the 'any' subsring arraylist with only
102         * one element.
103         */
104        public SubstringFilter()
105        {
106            super();
107        }
108    
109    
110        /**
111         * Get the internal substrings
112         * 
113         * @return Returns the anySubstrings.
114         */
115        public List<String> getAnySubstrings()
116        {
117            return anySubstrings;
118        }
119    
120    
121        /**
122         * Add a internal substring
123         * 
124         * @param any The anySubstrings to set.
125         */
126        public void addAnySubstrings( String any )
127        {
128            this.anySubstrings.add( any );
129        }
130    
131    
132        /**
133         * Get the final substring
134         * 
135         * @return Returns the finalSubstrings.
136         */
137        public String getFinalSubstrings()
138        {
139            return finalSubstrings;
140        }
141    
142    
143        /**
144         * Set the final substring
145         * 
146         * @param finalSubstrings The finalSubstrings to set.
147         */
148        public void setFinalSubstrings( String finalSubstrings )
149        {
150            this.finalSubstrings = finalSubstrings;
151        }
152    
153    
154        /**
155         * Get the initial substring
156         * 
157         * @return Returns the initialSubstrings.
158         */
159        public String getInitialSubstrings()
160        {
161            return initialSubstrings;
162        }
163    
164    
165        /**
166         * Set the initial substring
167         * 
168         * @param initialSubstrings The initialSubstrings to set.
169         */
170        public void setInitialSubstrings( String initialSubstrings )
171        {
172            this.initialSubstrings = initialSubstrings;
173        }
174    
175    
176        /**
177         * Get the attribute
178         * 
179         * @return Returns the type.
180         */
181        public String getType()
182        {
183            return type;
184        }
185    
186    
187        /**
188         * Set the attribute to match
189         * 
190         * @param type The type to set.
191         */
192        public void setType( String type )
193        {
194            this.type = type;
195        }
196    
197    
198        /**
199         * @return Returns the substringsLength.
200         */
201        public int getSubstringsLength()
202        {
203            return substringsLength;
204        }
205    
206    
207        /**
208         * @param substringsLength The substringsLength to set.
209         */
210        public void setSubstringsLength( int substringsLength )
211        {
212            this.substringsLength = substringsLength;
213        }
214    
215    
216        /**
217         * Compute the SubstringFilter length 
218         * 
219         * SubstringFilter : 
220         * 0xA4 L1 
221         *   | 
222         *   +--> 0x04 L2 type 
223         *   +--> 0x30 L3 
224         *          | 
225         *         [+--> 0x80 L4 initial] 
226         *         [+--> 0x81 L5-1 any] 
227         *         [+--> 0x81 L5-2 any] 
228         *         [+--> ... 
229         *         [+--> 0x81 L5-i any] 
230         *         [+--> ... 
231         *         [+--> 0x81 L5-n any] 
232         *         [+--> 0x82 L6 final]
233         */
234        public int computeLength()
235        {
236            // The type
237            typeLength = StringTools.getBytesUtf8( type ).length;
238            
239            substringsFilterLength = 1 + TLV.getNbBytes( typeLength ) + typeLength;
240            substringsFilterSequenceLength = 0;
241    
242            if ( initialSubstrings != null )
243            {
244                int initialLength = StringTools.getBytesUtf8( initialSubstrings ).length; 
245                substringsFilterSequenceLength += 1 + TLV.getNbBytes( initialLength )
246                    + initialLength;
247            }
248    
249            if ( anySubstrings != null )
250            {
251                for ( String any:anySubstrings )
252                {
253                    int anyLength = StringTools.getBytesUtf8( any ).length; 
254                    substringsFilterSequenceLength += 1 + TLV.getNbBytes( anyLength ) + anyLength;
255                }
256            }
257    
258            if ( finalSubstrings != null )
259            {
260                int finalLength = StringTools.getBytesUtf8( finalSubstrings ).length; 
261                substringsFilterSequenceLength += 1 + TLV.getNbBytes( finalLength )
262                    + finalLength;
263            }
264    
265            substringsFilterLength += 1 + TLV.getNbBytes( substringsFilterSequenceLength )
266                + substringsFilterSequenceLength;
267    
268            return 1 + TLV.getNbBytes( substringsFilterLength ) + substringsFilterLength;
269        }
270    
271    
272        /**
273         * Encode the Substrings Filter to a PDU. 
274         * 
275         * Substrings Filter :
276         * 
277         * 0xA4 LL 
278         * 0x30 LL substringsFilter
279         *   0x04 LL type
280         *   0x30 LL substrings sequence
281         *    |  0x80 LL initial
282         *    | /  [0x81 LL any]* 
283         *    |/   [0x82 LL final]
284         *    +--[0x81 LL any]+
285         *     \   [0x82 LL final]
286         *      \
287         *       0x82 LL final
288         * 
289         * @param buffer The buffer where to put the PDU
290         * @return The PDU.
291         */
292        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
293        {
294            if ( buffer == null )
295            {
296                throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
297            }
298    
299            try
300            {
301                // The SubstringFilter Tag
302                buffer.put( ( byte ) LdapConstants.SUBSTRINGS_FILTER_TAG );
303                buffer.put( TLV.getBytes( substringsFilterLength ) );
304    
305                // The type
306                Value.encode( buffer, type.getBytes() );
307    
308                // The SubstringSequenceFilter Tag
309                buffer.put( UniversalTag.SEQUENCE_TAG );
310                buffer.put( TLV.getBytes( substringsFilterSequenceLength ) );
311    
312                if ( ( initialSubstrings == null ) && ( ( anySubstrings == null ) || ( anySubstrings.size() == 0 ) )
313                    && ( finalSubstrings == null ) )
314                {
315                    throw new EncoderException( I18n.err( I18n.ERR_04058 ) );
316                }
317    
318                // The initial substring
319                if ( initialSubstrings != null )
320                {
321                    byte[] initialBytes = StringTools.getBytesUtf8( initialSubstrings );
322                    buffer.put( ( byte ) LdapConstants.SUBSTRINGS_FILTER_INITIAL_TAG );
323                    buffer.put( TLV.getBytes( initialBytes.length ) );
324                    buffer.put( initialBytes );
325                }
326    
327                // The any substrings
328                if ( anySubstrings != null )
329                {
330                    for ( String any:anySubstrings )
331                    {
332                        byte[] anyBytes = StringTools.getBytesUtf8( any );
333                        buffer.put( ( byte ) LdapConstants.SUBSTRINGS_FILTER_ANY_TAG );
334                        buffer.put( TLV.getBytes( anyBytes.length ) );
335                        buffer.put( anyBytes );
336                    }
337                }
338    
339                // The final substring
340                if ( finalSubstrings != null )
341                {
342                    byte[] finalBytes = StringTools.getBytesUtf8( finalSubstrings );
343                    buffer.put( ( byte ) LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG );
344                    buffer.put( TLV.getBytes( finalBytes.length ) );
345                    buffer.put( finalBytes );
346                }
347            }
348            catch ( BufferOverflowException boe )
349            {
350                throw new EncoderException( I18n.err( I18n.ERR_04005 ) );
351            }
352    
353            return buffer;
354        }
355    
356    
357        /**
358         * Return a string compliant with RFC 2254 representing a Substring filter
359         * 
360         * @return The substring filter string
361         */
362        public String toString()
363        {
364    
365            StringBuffer sb = new StringBuffer();
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    }