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 */ 020package org.apache.directory.shared.ldap.codec.search; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025import java.util.ArrayList; 026import java.util.List; 027 028import org.apache.directory.shared.asn1.EncoderException; 029import org.apache.directory.shared.asn1.ber.tlv.TLV; 030import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; 031import org.apache.directory.shared.asn1.ber.tlv.Value; 032import org.apache.directory.shared.i18n.I18n; 033import org.apache.directory.shared.ldap.codec.api.LdapConstants; 034import org.apache.directory.shared.util.Strings; 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 */ 053public class SubstringFilter extends Filter 054{ 055 // ~ Instance fields 056 // ---------------------------------------------------------------------------- 057 058 /** The substring filter type (an attributeDescription) */ 059 private String type; 060 061 /** The type length */ 062 private int typeLength; 063 064 /** 065 * This member is used to control the length of the three parts of the 066 * substring filter 067 */ 068 private int substringsLength; 069 070 /** The initial filter */ 071 private String initialSubstrings; 072 073 /** The any filter. It's a list of LdapString */ 074 private List<String> anySubstrings = new ArrayList<String>( 1 ); 075 076 /** The final filter */ 077 private String finalSubstrings; 078 079 /** Temporary storage for substringsFilter length */ 080 private int substringsFilterLength; 081 082 /** Temporary storage for substringsFilter sequence length */ 083 private int substringsFilterSequenceLength; 084 085 086 // ~ Methods 087 // ------------------------------------------------------------------------------------ 088 089 /** 090 * The constructor. We will create the 'any' subsring arraylist with only 091 * one element. 092 */ 093 public SubstringFilter( int tlvId ) 094 { 095 super( tlvId ); 096 } 097 098 099 /** 100 * The constructor. We will create the 'any' subsring arraylist with only 101 * one element. 102 */ 103 public SubstringFilter() 104 { 105 super(); 106 } 107 108 109 /** 110 * Get the internal substrings 111 * 112 * @return Returns the anySubstrings. 113 */ 114 public List<String> getAnySubstrings() 115 { 116 return anySubstrings; 117 } 118 119 120 /** 121 * Add a internal substring 122 * 123 * @param any The anySubstrings to set. 124 */ 125 public void addAnySubstrings( String any ) 126 { 127 this.anySubstrings.add( any ); 128 } 129 130 131 /** 132 * Get the final substring 133 * 134 * @return Returns the finalSubstrings. 135 */ 136 public String getFinalSubstrings() 137 { 138 return finalSubstrings; 139 } 140 141 142 /** 143 * Set the final substring 144 * 145 * @param finalSubstrings The finalSubstrings to set. 146 */ 147 public void setFinalSubstrings( String finalSubstrings ) 148 { 149 this.finalSubstrings = finalSubstrings; 150 } 151 152 153 /** 154 * Get the initial substring 155 * 156 * @return Returns the initialSubstrings. 157 */ 158 public String getInitialSubstrings() 159 { 160 return initialSubstrings; 161 } 162 163 164 /** 165 * Set the initial substring 166 * 167 * @param initialSubstrings The initialSubstrings to set. 168 */ 169 public void setInitialSubstrings( String initialSubstrings ) 170 { 171 this.initialSubstrings = initialSubstrings; 172 } 173 174 175 /** 176 * Get the attribute 177 * 178 * @return Returns the type. 179 */ 180 public String getType() 181 { 182 return type; 183 } 184 185 186 /** 187 * Set the attribute to match 188 * 189 * @param type The type to set. 190 */ 191 public void setType( String type ) 192 { 193 this.type = type; 194 } 195 196 197 /** 198 * @return Returns the substringsLength. 199 */ 200 public int getSubstringsLength() 201 { 202 return substringsLength; 203 } 204 205 206 /** 207 * @param substringsLength The substringsLength to set. 208 */ 209 public void setSubstringsLength( int substringsLength ) 210 { 211 this.substringsLength = substringsLength; 212 } 213 214 215 /** 216 * Compute the SubstringFilter length 217 * 218 * SubstringFilter : 219 * 0xA4 L1 220 * | 221 * +--> 0x04 L2 type 222 * +--> 0x30 L3 223 * | 224 * [+--> 0x80 L4 initial] 225 * [+--> 0x81 L5-1 any] 226 * [+--> 0x81 L5-2 any] 227 * [+--> ... 228 * [+--> 0x81 L5-i any] 229 * [+--> ... 230 * [+--> 0x81 L5-n any] 231 * [+--> 0x82 L6 final] 232 */ 233 public int computeLength() 234 { 235 // The type 236 typeLength = Strings.getBytesUtf8(type).length; 237 238 substringsFilterLength = 1 + TLV.getNbBytes( typeLength ) + typeLength; 239 substringsFilterSequenceLength = 0; 240 241 if ( initialSubstrings != null ) 242 { 243 int initialLength = Strings.getBytesUtf8(initialSubstrings).length; 244 substringsFilterSequenceLength += 1 + TLV.getNbBytes( initialLength ) 245 + initialLength; 246 } 247 248 if ( anySubstrings != null ) 249 { 250 for ( String any:anySubstrings ) 251 { 252 int anyLength = Strings.getBytesUtf8(any).length; 253 substringsFilterSequenceLength += 1 + TLV.getNbBytes( anyLength ) + anyLength; 254 } 255 } 256 257 if ( finalSubstrings != null ) 258 { 259 int finalLength = Strings.getBytesUtf8(finalSubstrings).length; 260 substringsFilterSequenceLength += 1 + TLV.getNbBytes( finalLength ) 261 + finalLength; 262 } 263 264 substringsFilterLength += 1 + TLV.getNbBytes( substringsFilterSequenceLength ) 265 + substringsFilterSequenceLength; 266 267 return 1 + TLV.getNbBytes( substringsFilterLength ) + substringsFilterLength; 268 } 269 270 271 /** 272 * Encode the Substrings Filter to a PDU. 273 * 274 * Substrings Filter : 275 * 276 * 0xA4 LL 277 * 0x30 LL substringsFilter 278 * 0x04 LL type 279 * 0x30 LL substrings sequence 280 * | 0x80 LL initial 281 * | / [0x81 LL any]* 282 * |/ [0x82 LL final] 283 * +--[0x81 LL any]+ 284 * \ [0x82 LL final] 285 * \ 286 * 0x82 LL final 287 * 288 * @param buffer The buffer where to put the PDU 289 * @return The PDU. 290 */ 291 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 292 { 293 if ( buffer == null ) 294 { 295 throw new EncoderException( I18n.err( I18n.ERR_04023 ) ); 296 } 297 298 try 299 { 300 // The SubstringFilter Tag 301 buffer.put( ( byte ) LdapConstants.SUBSTRINGS_FILTER_TAG ); 302 buffer.put( TLV.getBytes( substringsFilterLength ) ); 303 304 // The type 305 Value.encode( buffer, type.getBytes() ); 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.size() == 0 ) ) 312 && ( finalSubstrings == null ) ) 313 { 314 throw new EncoderException( I18n.err( I18n.ERR_04058 ) ); 315 } 316 317 // The initial substring 318 if ( initialSubstrings != null ) 319 { 320 byte[] initialBytes = Strings.getBytesUtf8(initialSubstrings); 321 buffer.put( ( byte ) LdapConstants.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 ) LdapConstants.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 ) LdapConstants.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_04005 ) ); 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 public String toString() 362 { 363 364 StringBuffer sb = new StringBuffer(); 365 366 if ( initialSubstrings != null ) 367 { 368 sb.append( initialSubstrings ); 369 } 370 371 sb.append( '*' ); 372 373 if ( anySubstrings != null ) 374 { 375 for ( String any:anySubstrings ) 376 { 377 sb.append( any ).append( '*' ); 378 } 379 } 380 381 if ( finalSubstrings != null ) 382 { 383 sb.append( finalSubstrings ); 384 } 385 386 return sb.toString(); 387 } 388}