001 /*
002 * Copyright 2011-2012 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
018 package com.unboundid.scim.sdk;
019
020 import org.json.JSONException;
021 import org.json.JSONObject;
022
023 import java.util.ArrayList;
024 import java.util.List;
025
026
027
028 /**
029 * This class represents a SCIM query filter.
030 */
031 public 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
106 return parser.parse();
107 }
108
109
110
111 /**
112 * Create a new and filter.
113 *
114 * @param filterComponents The filter components.
115 *
116 * @return A new and filter.
117 */
118 public static SCIMFilter createAndFilter(
119 final List<SCIMFilter> filterComponents)
120 {
121 return new SCIMFilter(SCIMFilterType.AND, null, null, false,
122 new ArrayList<SCIMFilter>(filterComponents));
123 }
124
125
126
127 /**
128 * Create a new or filter.
129 *
130 * @param filterComponents The filter components.
131 *
132 * @return A new or filter.
133 */
134 public static SCIMFilter createOrFilter(
135 final List<SCIMFilter> filterComponents)
136 {
137 return new SCIMFilter(SCIMFilterType.OR, null, null, false,
138 new ArrayList<SCIMFilter>(filterComponents));
139 }
140
141
142
143 /**
144 * Create a new equality filter.
145 *
146 * @param filterAttribute The attribute or sub-attribute to filter by.
147 * @param filterValue The filter attribute value.
148 *
149 * @return A new equality filter.
150 */
151 public static SCIMFilter createEqualityFilter(
152 final AttributePath filterAttribute, final String filterValue)
153 {
154 return new SCIMFilter(SCIMFilterType.EQUALITY, filterAttribute,
155 filterValue, true, null);
156 }
157
158
159
160 /**
161 * Create a new contains filter.
162 *
163 * @param filterAttribute The attribute or sub-attribute to filter by.
164 * @param filterValue The filter attribute value.
165 *
166 * @return A new contains filter.
167 */
168 public static SCIMFilter createContainsFilter(
169 final AttributePath filterAttribute, final String filterValue)
170 {
171 return new SCIMFilter(SCIMFilterType.CONTAINS, filterAttribute,
172 filterValue, true, null);
173 }
174
175
176
177 /**
178 * Create a new starts with filter.
179 *
180 * @param filterAttribute The attribute or sub-attribute to filter by.
181 * @param filterValue The filter attribute value.
182 *
183 * @return A new starts with filter.
184 */
185 public static SCIMFilter createStartsWithFilter(
186 final AttributePath filterAttribute, final String filterValue)
187 {
188 return new SCIMFilter(SCIMFilterType.STARTS_WITH, filterAttribute,
189 filterValue, true, null);
190 }
191
192
193
194 /**
195 * Create a new presence filter.
196 *
197 * @param filterAttribute The attribute or sub-attribute to filter by.
198 *
199 * @return A new presence filter.
200 */
201 public static SCIMFilter createPresenceFilter(
202 final AttributePath filterAttribute)
203 {
204 return new SCIMFilter(SCIMFilterType.PRESENCE, filterAttribute,
205 null, true, null);
206 }
207
208
209
210 /**
211 * Create a new greater than filter.
212 *
213 * @param filterAttribute The attribute or sub-attribute to filter by.
214 * @param filterValue The filter attribute value.
215 *
216 * @return A new greater than filter.
217 */
218 public static SCIMFilter createGreaterThanFilter(
219 final AttributePath filterAttribute, final String filterValue)
220 {
221 return new SCIMFilter(SCIMFilterType.GREATER_THAN, filterAttribute,
222 filterValue, true, null);
223 }
224
225
226
227 /**
228 * Create a new greater or equal filter.
229 *
230 * @param filterAttribute The attribute or sub-attribute to filter by.
231 * @param filterValue The filter attribute value.
232 *
233 * @return A new greater or equal filter.
234 */
235 public static SCIMFilter createGreaterOrEqualFilter(
236 final AttributePath filterAttribute, final String filterValue)
237 {
238 return new SCIMFilter(SCIMFilterType.GREATER_OR_EQUAL, filterAttribute,
239 filterValue, true, null);
240 }
241
242
243
244 /**
245 * Create a new less than filter.
246 *
247 * @param filterAttribute The attribute or sub-attribute to filter by.
248 * @param filterValue The filter attribute value.
249 *
250 * @return A new less than filter.
251 */
252 public static SCIMFilter createLessThanFilter(
253 final AttributePath filterAttribute, final String filterValue)
254 {
255 return new SCIMFilter(SCIMFilterType.LESS_THAN, filterAttribute,
256 filterValue, true, null);
257 }
258
259
260
261 /**
262 * Create a new less or equal filter.
263 *
264 * @param filterAttribute The attribute or sub-attribute to filter by.
265 * @param filterValue The filter attribute value.
266 *
267 * @return A new less or equal filter.
268 */
269 public static SCIMFilter createLessOrEqualFilter(
270 final AttributePath filterAttribute, final String filterValue)
271 {
272 return new SCIMFilter(SCIMFilterType.LESS_OR_EQUAL, filterAttribute,
273 filterValue, true, null);
274 }
275
276
277
278 /**
279 * Retrieve the filter type.
280 *
281 * @return The filter type.
282 */
283 public SCIMFilterType getFilterType()
284 {
285 return filterType;
286 }
287
288
289
290 /**
291 * Retrieve the attribute or sub-attribute to filter by, or {@code null} if
292 * not applicable for this filter type.
293 *
294 * @return The attribute or sub-attribute to filter by
295 */
296 public AttributePath getFilterAttribute()
297 {
298 return filterAttribute;
299 }
300
301
302
303 /**
304 * Retrieve the filter attribute value.
305 *
306 * @return The filter attribute value, or {@code null} if not applicable
307 * for this filter type.
308 */
309 public String getFilterValue()
310 {
311 return filterValue;
312 }
313
314
315
316 /**
317 * Determine whether the filter attribute value is quoted in the string
318 * representation of the filter.
319 *
320 * @return {@code true} if the filter attribute value is quoted in the string
321 * representation of the filter.
322 */
323 public boolean isQuoteFilterValue()
324 {
325 return quoteFilterValue;
326 }
327
328
329
330 /**
331 * Retrieve the filter components for an 'and' or 'or' filter.
332 *
333 * @return The filter components for an 'and' or 'or' filter.
334 */
335 public List<SCIMFilter> getFilterComponents()
336 {
337 return filterComponents;
338 }
339
340
341
342 /**
343 * {@inheritDoc}
344 */
345 @Override
346 public String toString()
347 {
348 final StringBuilder builder = new StringBuilder();
349 toString(builder);
350 return builder.toString();
351 }
352
353
354
355 /**
356 * Append the string representation of the filter to the provided buffer.
357 *
358 * @param builder The buffer to which the string representation of the
359 * filter is to be appended.
360 */
361 public void toString(final StringBuilder builder)
362 {
363 switch (filterType)
364 {
365 case AND:
366 case OR:
367 builder.append('(');
368
369 for (int i = 0; i < filterComponents.size(); i++)
370 {
371 if (i != 0)
372 {
373 builder.append(' ');
374 builder.append(filterType);
375 builder.append(' ');
376 }
377
378 builder.append(filterComponents.get(i));
379 }
380
381 builder.append(')');
382 break;
383
384 case EQUALITY:
385 case CONTAINS:
386 case STARTS_WITH:
387 case GREATER_THAN:
388 case GREATER_OR_EQUAL:
389 case LESS_THAN:
390 case LESS_OR_EQUAL:
391 builder.append(filterAttribute);
392 builder.append(' ');
393 builder.append(filterType);
394 builder.append(' ');
395
396 if (quoteFilterValue)
397 {
398 try
399 {
400 builder.append(JSONObject.valueToString(filterValue));
401 }
402 catch (JSONException e)
403 {
404 Debug.debugException(e);
405 }
406 }
407 else
408 {
409 builder.append(filterValue);
410 }
411 break;
412
413 case PRESENCE:
414 builder.append(filterAttribute);
415 builder.append(' ');
416 builder.append(filterType);
417 break;
418 }
419 }
420 }