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 22:52:31 +0200 (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 }