001/* 002 * Copyright 2011-2016 UnboundID Corp. 003 * 004 * This program is free software; you can redistribute it and/or modify 005 * it under the terms of the GNU General Public License (GPLv2 only) 006 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 007 * as published by the Free Software Foundation. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU General Public License for more details. 013 * 014 * You should have received a copy of the GNU General Public License 015 * along with this program; if not, see <http://www.gnu.org/licenses>. 016 */ 017 018package com.unboundid.scim.sdk; 019 020import org.json.JSONException; 021import org.json.JSONObject; 022 023import java.util.ArrayList; 024import java.util.List; 025 026 027 028/** 029 * This class represents a SCIM query filter. 030 */ 031public class SCIMFilter 032{ 033 /** 034 * The filter type. 035 */ 036 private final SCIMFilterType filterType; 037 038 /** 039 * The attribute or sub-attribute to filter by, or {@code null} if not 040 * applicable. 041 */ 042 private final AttributePath filterAttribute; 043 044 /** 045 * The filter attribute value, or {@code null} if not applicable. 046 */ 047 private final String filterValue; 048 049 /** 050 * Specifies whether the filter value is quoted in the string representation 051 * of the filter. String and DateTime values are quoted. Integer and Boolean 052 * values are not quoted. 053 */ 054 private final boolean quoteFilterValue; 055 056 /** 057 * The filter components for 'or' and 'and' filter types, or {@code null} 058 * if not applicable. 059 */ 060 private final List<SCIMFilter> filterComponents; 061 062 063 064 /** 065 * Create a new SCIM filter from the provided information. 066 * 067 * @param filterType The filter type. 068 * @param filterAttribute The attribute or sub-attribute to filter by, or 069 * {@code null} if not applicable. 070 * @param filterValue The filter attribute value, or {@code null} if not 071 * applicable. 072 * @param quoteFilterValue Specifies whether the filter value is quoted in 073 * the string representation of the filter. 074 * @param filterComponents The filter components for 'or' and 'and' filter 075 * types, or {@code null} if not applicable. 076 */ 077 public SCIMFilter(final SCIMFilterType filterType, 078 final AttributePath filterAttribute, 079 final String filterValue, 080 final boolean quoteFilterValue, 081 final List<SCIMFilter> filterComponents) 082 { 083 this.filterType = filterType; 084 this.filterAttribute = filterAttribute; 085 this.filterValue = filterValue; 086 this.quoteFilterValue = quoteFilterValue; 087 this.filterComponents = filterComponents; 088 } 089 090 091 092 /** 093 * Parse a filter from its string representation. 094 * 095 * @param filterString The string representation of the filter expression. 096 * 097 * @return The parsed filter. 098 * 099 * @throws SCIMException If the filter string could not be parsed. 100 */ 101 public static SCIMFilter parse(final String filterString) 102 throws SCIMException 103 { 104 final FilterParser parser = new FilterParser(filterString, 105 SCIMConstants.SCHEMA_URI_CORE); 106 return parser.parse(); 107 } 108 109 110 111 /** 112 * Parse a filter from its string representation. 113 * 114 * @param filterString The string representation of the filter expression. 115 * @param defaultSchema The default schema that should be assumed when parsing 116 * attributes without the schema explicitly defined in 117 * the URN. 118 * 119 * @return The parsed filter. 120 * 121 * @throws SCIMException If the filter string could not be parsed. 122 */ 123 public static SCIMFilter parse(final String filterString, 124 final String defaultSchema) 125 throws SCIMException 126 { 127 final FilterParser parser = new FilterParser(filterString, defaultSchema); 128 return parser.parse(); 129 } 130 131 132 133 /** 134 * Create a new and filter. 135 * 136 * @param filterComponents The filter components. 137 * 138 * @return A new and filter. 139 */ 140 public static SCIMFilter createAndFilter( 141 final List<SCIMFilter> filterComponents) 142 { 143 return new SCIMFilter(SCIMFilterType.AND, null, null, false, 144 new ArrayList<SCIMFilter>(filterComponents)); 145 } 146 147 148 149 /** 150 * Create a new or filter. 151 * 152 * @param filterComponents The filter components. 153 * 154 * @return A new or filter. 155 */ 156 public static SCIMFilter createOrFilter( 157 final List<SCIMFilter> filterComponents) 158 { 159 return new SCIMFilter(SCIMFilterType.OR, null, null, false, 160 new ArrayList<SCIMFilter>(filterComponents)); 161 } 162 163 164 165 /** 166 * Create a new equality filter. 167 * 168 * @param filterAttribute The attribute or sub-attribute to filter by. 169 * @param filterValue The filter attribute value. 170 * 171 * @return A new equality filter. 172 */ 173 public static SCIMFilter createEqualityFilter( 174 final AttributePath filterAttribute, final String filterValue) 175 { 176 return new SCIMFilter(SCIMFilterType.EQUALITY, filterAttribute, 177 filterValue, true, null); 178 } 179 180 181 182 /** 183 * Create a new contains filter. 184 * 185 * @param filterAttribute The attribute or sub-attribute to filter by. 186 * @param filterValue The filter attribute value. 187 * 188 * @return A new contains filter. 189 */ 190 public static SCIMFilter createContainsFilter( 191 final AttributePath filterAttribute, final String filterValue) 192 { 193 return new SCIMFilter(SCIMFilterType.CONTAINS, filterAttribute, 194 filterValue, true, null); 195 } 196 197 198 199 /** 200 * Create a new starts with filter. 201 * 202 * @param filterAttribute The attribute or sub-attribute to filter by. 203 * @param filterValue The filter attribute value. 204 * 205 * @return A new starts with filter. 206 */ 207 public static SCIMFilter createStartsWithFilter( 208 final AttributePath filterAttribute, final String filterValue) 209 { 210 return new SCIMFilter(SCIMFilterType.STARTS_WITH, filterAttribute, 211 filterValue, true, null); 212 } 213 214 215 216 /** 217 * Create a new presence filter. 218 * 219 * @param filterAttribute The attribute or sub-attribute to filter by. 220 * 221 * @return A new presence filter. 222 */ 223 public static SCIMFilter createPresenceFilter( 224 final AttributePath filterAttribute) 225 { 226 return new SCIMFilter(SCIMFilterType.PRESENCE, filterAttribute, 227 null, true, null); 228 } 229 230 231 232 /** 233 * Create a new greater than filter. 234 * 235 * @param filterAttribute The attribute or sub-attribute to filter by. 236 * @param filterValue The filter attribute value. 237 * 238 * @return A new greater than filter. 239 */ 240 public static SCIMFilter createGreaterThanFilter( 241 final AttributePath filterAttribute, final String filterValue) 242 { 243 return new SCIMFilter(SCIMFilterType.GREATER_THAN, filterAttribute, 244 filterValue, true, null); 245 } 246 247 248 249 /** 250 * Create a new greater or equal filter. 251 * 252 * @param filterAttribute The attribute or sub-attribute to filter by. 253 * @param filterValue The filter attribute value. 254 * 255 * @return A new greater or equal filter. 256 */ 257 public static SCIMFilter createGreaterOrEqualFilter( 258 final AttributePath filterAttribute, final String filterValue) 259 { 260 return new SCIMFilter(SCIMFilterType.GREATER_OR_EQUAL, filterAttribute, 261 filterValue, true, null); 262 } 263 264 265 266 /** 267 * Create a new less than filter. 268 * 269 * @param filterAttribute The attribute or sub-attribute to filter by. 270 * @param filterValue The filter attribute value. 271 * 272 * @return A new less than filter. 273 */ 274 public static SCIMFilter createLessThanFilter( 275 final AttributePath filterAttribute, final String filterValue) 276 { 277 return new SCIMFilter(SCIMFilterType.LESS_THAN, filterAttribute, 278 filterValue, true, null); 279 } 280 281 282 283 /** 284 * Create a new less or equal filter. 285 * 286 * @param filterAttribute The attribute or sub-attribute to filter by. 287 * @param filterValue The filter attribute value. 288 * 289 * @return A new less or equal filter. 290 */ 291 public static SCIMFilter createLessOrEqualFilter( 292 final AttributePath filterAttribute, final String filterValue) 293 { 294 return new SCIMFilter(SCIMFilterType.LESS_OR_EQUAL, filterAttribute, 295 filterValue, true, null); 296 } 297 298 299 300 /** 301 * Retrieve the filter type. 302 * 303 * @return The filter type. 304 */ 305 public SCIMFilterType getFilterType() 306 { 307 return filterType; 308 } 309 310 311 312 /** 313 * Retrieve the attribute or sub-attribute to filter by, or {@code null} if 314 * not applicable for this filter type. 315 * 316 * @return The attribute or sub-attribute to filter by 317 */ 318 public AttributePath getFilterAttribute() 319 { 320 return filterAttribute; 321 } 322 323 324 325 /** 326 * Retrieve the filter attribute value. 327 * 328 * @return The filter attribute value, or {@code null} if not applicable 329 * for this filter type. 330 */ 331 public String getFilterValue() 332 { 333 return filterValue; 334 } 335 336 337 338 /** 339 * Determine whether the filter attribute value is quoted in the string 340 * representation of the filter. 341 * 342 * @return {@code true} if the filter attribute value is quoted in the string 343 * representation of the filter. 344 */ 345 public boolean isQuoteFilterValue() 346 { 347 return quoteFilterValue; 348 } 349 350 351 352 /** 353 * Retrieve the filter components for an 'and' or 'or' filter. 354 * 355 * @return The filter components for an 'and' or 'or' filter. 356 */ 357 public List<SCIMFilter> getFilterComponents() 358 { 359 return filterComponents; 360 } 361 362 363 364 /** 365 * {@inheritDoc} 366 */ 367 @Override 368 public String toString() 369 { 370 final StringBuilder builder = new StringBuilder(); 371 toString(builder); 372 return builder.toString(); 373 } 374 375 376 377 /** 378 * Append the string representation of the filter to the provided buffer. 379 * 380 * @param builder The buffer to which the string representation of the 381 * filter is to be appended. 382 */ 383 public void toString(final StringBuilder builder) 384 { 385 switch (filterType) 386 { 387 case AND: 388 case OR: 389 builder.append('('); 390 391 for (int i = 0; i < filterComponents.size(); i++) 392 { 393 if (i != 0) 394 { 395 builder.append(' '); 396 builder.append(filterType); 397 builder.append(' '); 398 } 399 400 builder.append(filterComponents.get(i)); 401 } 402 403 builder.append(')'); 404 break; 405 406 case EQUALITY: 407 case CONTAINS: 408 case STARTS_WITH: 409 case GREATER_THAN: 410 case GREATER_OR_EQUAL: 411 case LESS_THAN: 412 case LESS_OR_EQUAL: 413 builder.append(filterAttribute); 414 builder.append(' '); 415 builder.append(filterType); 416 builder.append(' '); 417 418 if (quoteFilterValue) 419 { 420 try 421 { 422 builder.append(JSONObject.valueToString(filterValue)); 423 } 424 catch (JSONException e) 425 { 426 Debug.debugException(e); 427 } 428 } 429 else 430 { 431 builder.append(filterValue); 432 } 433 break; 434 435 case PRESENCE: 436 builder.append(filterAttribute); 437 builder.append(' '); 438 builder.append(filterType); 439 break; 440 } 441 } 442}