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.model.filter; 021 022 023import java.util.ArrayList; 024import java.util.List; 025import java.util.regex.Pattern; 026import java.util.regex.PatternSyntaxException; 027 028import org.apache.directory.api.ldap.model.entry.StringValue; 029import org.apache.directory.api.ldap.model.exception.LdapException; 030import org.apache.directory.api.ldap.model.schema.AttributeType; 031import org.apache.directory.api.ldap.model.schema.Normalizer; 032 033 034/** 035 * Filter expression tree node used to represent a substring assertion. 036 * 037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 038 */ 039public class SubstringNode extends LeafNode 040{ 041 /** The initial fragment before any wildcard */ 042 private String initialPattern; 043 044 /** The end fragment after wildcard */ 045 private String finalPattern; 046 047 /** List of fragments between wildcard */ 048 private List<String> anyPattern; 049 050 051 /** 052 * Creates a new SubstringNode object with only one wildcard and no internal 053 * any fragments between wildcards. 054 * 055 * @param attributeType the name of the attributeType to substring assert 056 * @param initialPattern the initial fragment 057 * @param finalPattern the final fragment 058 */ 059 public SubstringNode( AttributeType attributeType, String initialPattern, String finalPattern ) 060 { 061 super( attributeType, AssertionType.SUBSTRING ); 062 063 anyPattern = new ArrayList<String>( 2 ); 064 this.finalPattern = finalPattern; 065 this.initialPattern = initialPattern; 066 } 067 068 069 /** 070 * Creates a new SubstringNode object with only one wildcard and no internal 071 * any fragments between wildcards. 072 * 073 * @param attribute the name of the attribute to substring assert 074 * @param initialPattern the initial fragment 075 * @param finalPattern the final fragment 076 */ 077 public SubstringNode( String attribute, String initialPattern, String finalPattern ) 078 { 079 super( attribute, AssertionType.SUBSTRING ); 080 081 anyPattern = new ArrayList<String>( 2 ); 082 this.finalPattern = finalPattern; 083 this.initialPattern = initialPattern; 084 } 085 086 087 /** 088 * Creates a new SubstringNode object without any value 089 * 090 * @param attribute the name of the attribute to substring assert 091 */ 092 public SubstringNode( AttributeType attribute ) 093 { 094 super( attribute, AssertionType.SUBSTRING ); 095 096 anyPattern = new ArrayList<String>( 2 ); 097 this.finalPattern = null; 098 this.initialPattern = null; 099 } 100 101 102 /** 103 * Creates a new SubstringNode object without any value 104 * 105 * @param attributeType the attributeType to substring assert 106 */ 107 public SubstringNode( String attributeType ) 108 { 109 super( attributeType, AssertionType.SUBSTRING ); 110 111 anyPattern = new ArrayList<String>( 2 ); 112 this.finalPattern = null; 113 this.initialPattern = null; 114 } 115 116 117 /** 118 * Creates a new SubstringNode object more than one wildcard and an any 119 * list. 120 * 121 * @param anyPattern list of internal fragments between wildcards 122 * @param attributeType the attributeType to substring assert 123 * @param initialPattern the initial fragment 124 * @param finalPattern the final fragment 125 */ 126 public SubstringNode( List<String> anyPattern, AttributeType attributeType, String initialPattern, 127 String finalPattern ) 128 { 129 super( attributeType, AssertionType.SUBSTRING ); 130 131 this.anyPattern = anyPattern; 132 this.finalPattern = finalPattern; 133 this.initialPattern = initialPattern; 134 } 135 136 137 /** 138 * Creates a new SubstringNode object more than one wildcard and an any 139 * list. 140 * 141 * @param anyPattern list of internal fragments between wildcards 142 * @param attribute the name of the attribute to substring assert 143 * @param initialPattern the initial fragment 144 * @param finalPattern the final fragment 145 */ 146 public SubstringNode( List<String> anyPattern, String attribute, String initialPattern, String finalPattern ) 147 { 148 super( attribute, AssertionType.SUBSTRING ); 149 150 this.anyPattern = anyPattern; 151 this.finalPattern = finalPattern; 152 this.initialPattern = initialPattern; 153 } 154 155 156 /** 157 * Creates a regular expression from an LDAP substring assertion filter 158 * specification. 159 * 160 * @param initialPattern 161 * the initial fragment before wildcards 162 * @param anyPattern 163 * fragments surrounded by wildcards if any 164 * @param finalPattern 165 * the final fragment after last wildcard if any 166 * @return the regular expression for the substring match filter 167 * @throws java.util.regex.PatternSyntaxException 168 * if a syntactically correct regular expression cannot be 169 * compiled 170 */ 171 public static Pattern getRegex( String initialPattern, String[] anyPattern, String finalPattern ) 172 throws PatternSyntaxException 173 { 174 StringBuffer buf = new StringBuffer(); 175 176 if ( initialPattern != null ) 177 { 178 buf.append( '^' ).append( Pattern.quote( initialPattern ) ); 179 } 180 181 if ( anyPattern != null ) 182 { 183 for ( int i = 0; i < anyPattern.length; i++ ) 184 { 185 buf.append( ".*" ).append( Pattern.quote( anyPattern[i] ) ); 186 } 187 } 188 189 if ( finalPattern != null ) 190 { 191 buf.append( ".*" ).append( Pattern.quote( finalPattern ) ); 192 } 193 else 194 { 195 buf.append( ".*" ); 196 } 197 198 return Pattern.compile( buf.toString() ); 199 } 200 201 202 /** 203 * Clone the Node 204 */ 205 @Override 206 public ExprNode clone() 207 { 208 ExprNode clone = ( ExprNode ) super.clone(); 209 210 if ( anyPattern != null ) 211 { 212 ( ( SubstringNode ) clone ).anyPattern = new ArrayList<String>(); 213 214 for ( String any : anyPattern ) 215 { 216 ( ( SubstringNode ) clone ).anyPattern.add( any ); 217 } 218 } 219 220 return clone; 221 } 222 223 224 /** 225 * Gets the initial fragment. 226 * 227 * @return the initial prefix 228 */ 229 public final String getInitial() 230 { 231 return initialPattern; 232 } 233 234 235 /** 236 * Set the initial pattern 237 * @param initialPattern The initial pattern 238 */ 239 public void setInitial( String initialPattern ) 240 { 241 this.initialPattern = initialPattern; 242 } 243 244 245 /** 246 * Gets the final fragment or suffix. 247 * 248 * @return the suffix 249 */ 250 public final String getFinal() 251 { 252 return finalPattern; 253 } 254 255 256 /** 257 * Set the final pattern 258 * @param finalPattern The final pattern 259 */ 260 public void setFinal( String finalPattern ) 261 { 262 this.finalPattern = finalPattern; 263 } 264 265 266 /** 267 * Gets the list of wildcard surrounded any fragments. 268 * 269 * @return the any fragments 270 */ 271 public final List<String> getAny() 272 { 273 return anyPattern; 274 } 275 276 277 /** 278 * Set the any patterns 279 * @param anyPattern The any patterns 280 */ 281 public void setAny( List<String> anyPattern ) 282 { 283 this.anyPattern = anyPattern; 284 } 285 286 287 /** 288 * Add an any pattern 289 * @param anyPattern The any pattern 290 */ 291 public void addAny( String anyPattern ) 292 { 293 this.anyPattern.add( anyPattern ); 294 } 295 296 297 /** 298 * Gets the compiled regular expression for the substring expression. 299 * 300 * @param normalizer the normalizer to use for pattern component normalization 301 * @return the equivalent compiled regular expression 302 * @throws LdapException if there are problems while normalizing 303 */ 304 public final Pattern getRegex( Normalizer normalizer ) throws LdapException 305 { 306 if ( ( anyPattern != null ) && ( anyPattern.size() > 0 ) ) 307 { 308 String[] any = new String[anyPattern.size()]; 309 310 for ( int i = 0; i < any.length; i++ ) 311 { 312 any[i] = ( String ) normalizer.normalize( anyPattern.get( i ) ); 313 314 if ( any[i].length() == 0 ) 315 { 316 any[i] = " "; 317 } 318 } 319 320 String initialStr = null; 321 322 if ( initialPattern != null ) 323 { 324 initialStr = ( String ) normalizer.normalize( initialPattern ); 325 } 326 327 String finalStr = null; 328 329 if ( finalPattern != null ) 330 { 331 finalStr = ( String ) normalizer.normalize( finalPattern ); 332 } 333 334 return getRegex( initialStr, any, finalStr ); 335 } 336 337 String initialStr = null; 338 339 if ( initialPattern != null ) 340 { 341 initialStr = ( String ) normalizer.normalize( initialPattern ); 342 } 343 344 String finalStr = null; 345 346 if ( finalPattern != null ) 347 { 348 finalStr = ( String ) normalizer.normalize( finalPattern ); 349 } 350 351 return getRegex( initialStr, null, finalStr ); 352 } 353 354 355 /** 356 * {@inheritDoc} 357 */ 358 @Override 359 public boolean equals( Object obj ) 360 { 361 if ( obj == this ) 362 { 363 return true; 364 } 365 366 if ( ( obj == null ) || !( obj instanceof SubstringNode ) ) 367 { 368 return false; 369 } 370 SubstringNode that = ( SubstringNode ) obj; 371 372 if ( initialPattern == null ) 373 { 374 if ( that.initialPattern != null ) 375 { 376 return false; 377 } 378 } 379 else 380 { 381 if ( !initialPattern.equals( that.initialPattern ) ) 382 { 383 return false; 384 } 385 } 386 387 if ( finalPattern == null ) 388 { 389 if ( that.finalPattern != null ) 390 { 391 return false; 392 } 393 } 394 else 395 { 396 if ( !finalPattern.equals( that.finalPattern ) ) 397 { 398 return false; 399 } 400 } 401 402 return super.equals( obj ); 403 } 404 405 406 /** 407 * @see Object#hashCode() 408 * @return the instance's hash code 409 */ 410 @Override 411 public int hashCode() 412 { 413 int h = 37; 414 415 h = h * 17 + super.hashCode(); 416 h = h * 17 + ( initialPattern != null ? initialPattern.hashCode() : 0 ); 417 418 if ( anyPattern != null ) 419 { 420 for ( String pattern : anyPattern ) 421 { 422 h = h * 17 + pattern.hashCode(); 423 } 424 } 425 426 h = h * 17 + ( finalPattern != null ? finalPattern.hashCode() : 0 ); 427 428 return h; 429 } 430 431 432 /** 433 * @see java.lang.Object#toString() 434 * @return A string representing the AndNode 435 */ 436 public String toString() 437 { 438 StringBuilder buf = new StringBuilder(); 439 440 buf.append( '(' ); 441 442 if ( attributeType != null ) 443 { 444 buf.append( attributeType.getName() ); 445 } 446 else 447 { 448 buf.append( attribute ); 449 } 450 451 buf.append( '=' ); 452 453 if ( null != initialPattern ) 454 { 455 buf.append( escapeFilterValue( new StringValue( initialPattern ) ) ).append( '*' ); 456 } 457 else 458 { 459 buf.append( '*' ); 460 } 461 462 if ( null != anyPattern ) 463 { 464 for ( String any : anyPattern ) 465 { 466 buf.append( escapeFilterValue( new StringValue( any ) ) ); 467 buf.append( '*' ); 468 } 469 } 470 471 if ( null != finalPattern ) 472 { 473 buf.append( escapeFilterValue( new StringValue( finalPattern ) ) ); 474 } 475 476 buf.append( super.toString() ); 477 478 buf.append( ')' ); 479 480 return buf.toString(); 481 } 482}