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.api.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.api.asn1.EncoderException; 029import org.apache.directory.api.asn1.ber.tlv.BerValue; 030import org.apache.directory.api.asn1.ber.tlv.TLV; 031import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 032import org.apache.directory.api.i18n.I18n; 033import org.apache.directory.api.ldap.codec.api.LdapConstants; 034import org.apache.directory.api.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 /** The substring filter type (an attributeDescription) */ 056 private String type; 057 058 /** 059 * This member is used to control the length of the three parts of the 060 * substring filter 061 */ 062 private int substringsLength; 063 064 /** The initial filter */ 065 private String initialSubstrings; 066 067 /** The any filter. It's a list of LdapString */ 068 private List<String> anySubstrings = new ArrayList<String>( 1 ); 069 070 /** The final filter */ 071 private String finalSubstrings; 072 073 /** Temporary storage for substringsFilter length */ 074 private int substringsFilterLength; 075 076 /** Temporary storage for substringsFilter sequence length */ 077 private int substringsFilterSequenceLength; 078 079 080 // ~ Methods 081 // ------------------------------------------------------------------------------------ 082 083 /** 084 * The constructor. We will create the 'any' subsring arraylist with only 085 * one element. 086 */ 087 public SubstringFilter( int tlvId ) 088 { 089 super( tlvId ); 090 } 091 092 093 /** 094 * The constructor. We will create the 'any' subsring arraylist with only 095 * one element. 096 */ 097 public SubstringFilter() 098 { 099 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}