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.LdapCodecConstants; 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<>( 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 /** 081 * The constructor. We will create the 'any' subsring arraylist with only 082 * one element. 083 * 084 * @param tlvId The TLV identifier 085 */ 086 public SubstringFilter( int tlvId ) 087 { 088 super( tlvId ); 089 } 090 091 092 /** 093 * The constructor. We will create the 'any' subsring arraylist with only 094 * one element. 095 */ 096 public SubstringFilter() 097 { 098 super(); 099 } 100 101 102 /** 103 * Get the internal substrings 104 * 105 * @return Returns the anySubstrings. 106 */ 107 public List<String> getAnySubstrings() 108 { 109 return anySubstrings; 110 } 111 112 113 /** 114 * Add a internal substring 115 * 116 * @param any The anySubstrings to set. 117 */ 118 public void addAnySubstrings( String any ) 119 { 120 this.anySubstrings.add( any ); 121 } 122 123 124 /** 125 * Get the final substring 126 * 127 * @return Returns the finalSubstrings. 128 */ 129 public String getFinalSubstrings() 130 { 131 return finalSubstrings; 132 } 133 134 135 /** 136 * Set the final substring 137 * 138 * @param finalSubstrings The finalSubstrings to set. 139 */ 140 public void setFinalSubstrings( String finalSubstrings ) 141 { 142 this.finalSubstrings = finalSubstrings; 143 } 144 145 146 /** 147 * Get the initial substring 148 * 149 * @return Returns the initialSubstrings. 150 */ 151 public String getInitialSubstrings() 152 { 153 return initialSubstrings; 154 } 155 156 157 /** 158 * Set the initial substring 159 * 160 * @param initialSubstrings The initialSubstrings to set. 161 */ 162 public void setInitialSubstrings( String initialSubstrings ) 163 { 164 this.initialSubstrings = initialSubstrings; 165 } 166 167 168 /** 169 * Get the attribute 170 * 171 * @return Returns the type. 172 */ 173 public String getType() 174 { 175 return type; 176 } 177 178 179 /** 180 * Set the attribute to match 181 * 182 * @param type The type to set. 183 */ 184 public void setType( String type ) 185 { 186 this.type = type; 187 } 188 189 190 /** 191 * @return Returns the substringsLength. 192 */ 193 public int getSubstringsLength() 194 { 195 return substringsLength; 196 } 197 198 199 /** 200 * @param substringsLength The substringsLength to set. 201 */ 202 public void setSubstringsLength( int substringsLength ) 203 { 204 this.substringsLength = substringsLength; 205 } 206 207 208 /** 209 * Compute the SubstringFilter length 210 * <br> 211 * SubstringFilter : 212 * <pre> 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 * </pre> 227 * 228 * @return The encoded length 229 */ 230 @Override 231 public int computeLength() 232 { 233 // The type 234 int typeLength = Strings.getBytesUtf8( type ).length; 235 236 substringsFilterLength = 1 + TLV.getNbBytes( typeLength ) + typeLength; 237 substringsFilterSequenceLength = 0; 238 239 if ( initialSubstrings != null ) 240 { 241 int initialLength = Strings.getBytesUtf8( initialSubstrings ).length; 242 substringsFilterSequenceLength += 1 + TLV.getNbBytes( initialLength ) 243 + initialLength; 244 } 245 246 if ( anySubstrings != null ) 247 { 248 for ( String any : anySubstrings ) 249 { 250 int anyLength = Strings.getBytesUtf8( any ).length; 251 substringsFilterSequenceLength += 1 + TLV.getNbBytes( anyLength ) + anyLength; 252 } 253 } 254 255 if ( finalSubstrings != null ) 256 { 257 int finalLength = Strings.getBytesUtf8( finalSubstrings ).length; 258 substringsFilterSequenceLength += 1 + TLV.getNbBytes( finalLength ) 259 + finalLength; 260 } 261 262 substringsFilterLength += 1 + TLV.getNbBytes( substringsFilterSequenceLength ) 263 + substringsFilterSequenceLength; 264 265 return 1 + TLV.getNbBytes( substringsFilterLength ) + substringsFilterLength; 266 } 267 268 269 /** 270 * Encode the Substrings Filter to a PDU. 271 * <br> 272 * Substrings Filter : 273 * <pre> 274 * 0xA4 LL 275 * 0x30 LL substringsFilter 276 * 0x04 LL type 277 * 0x30 LL substrings sequence 278 * | 0x80 LL initial 279 * | / [0x81 LL any]* 280 * |/ [0x82 LL final] 281 * +--[0x81 LL any]+ 282 * \ [0x82 LL final] 283 * \ 284 * 0x82 LL final 285 * </pre> 286 * 287 * @param buffer The buffer where to put the PDU 288 * @return The PDU. 289 */ 290 @Override 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 ) LdapCodecConstants.SUBSTRINGS_FILTER_TAG ); 302 buffer.put( TLV.getBytes( substringsFilterLength ) ); 303 304 // The type 305 BerValue.encode( buffer, Strings.getBytesUtf8( type ) ); 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.isEmpty() ) 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 ) LdapCodecConstants.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 ) LdapCodecConstants.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 ) LdapCodecConstants.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 ), boe ); 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 @Override 362 public String toString() 363 { 364 365 StringBuilder sb = new StringBuilder(); 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}