001 /*
002 * Copyright 2015 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2015 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.unboundidds.jsonfilter;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Collection;
027 import java.util.Collections;
028 import java.util.HashSet;
029 import java.util.LinkedHashMap;
030 import java.util.List;
031 import java.util.Set;
032
033 import com.unboundid.util.Mutable;
034 import com.unboundid.util.StaticUtils;
035 import com.unboundid.util.ThreadSafety;
036 import com.unboundid.util.ThreadSafetyLevel;
037 import com.unboundid.util.json.JSONArray;
038 import com.unboundid.util.json.JSONException;
039 import com.unboundid.util.json.JSONObject;
040 import com.unboundid.util.json.JSONString;
041 import com.unboundid.util.json.JSONValue;
042
043
044
045 /**
046 * <BLOCKQUOTE>
047 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
048 * LDAP SDK for Java. It is not available for use in applications that
049 * include only the Standard Edition of the LDAP SDK, and is not supported for
050 * use in conjunction with non-UnboundID products.
051 * </BLOCKQUOTE>
052 * This class provides an implementation of a JSON object filter that can
053 * perform a logical AND across the result obtained from a number of filters.
054 * The AND filter will match an object only if all of the filters contained in
055 * it match that object. An AND filter with an empty set of embedded filters
056 * will match any object.
057 * <BR><BR>
058 * The fields that are required to be included in an "AND" filter are:
059 * <UL>
060 * <LI>
061 * {@code andFilters} -- An array of JSON objects, each of which is a valid
062 * JSON object filter. Each of these filters must match a JSON object in
063 * order for the AND filter to match. If this is an empty array, then the
064 * filter will match any object.
065 * </LI>
066 * </UL>
067 * <BR><BR>
068 * <H2>Examples</H2>
069 * The following is an example of an AND filter that will match any JSON object:
070 * <PRE>
071 * { "filterType" : "and",
072 * "andFilters" : [ ] }
073 * </PRE>
074 * The above filter can be created with the code:
075 * <PRE>
076 * ANDJSONObjectFilter filter = new ANDJSONObjectFilter();
077 * </PRE>
078 * <BR><BR>
079 * The following is an example of an AND filter that will match any JSON object
080 * in which there is a top-level field named "firstName" with a String value of
081 * "John" and top-level field named "lastName" with a String value of "Doe":
082 * <PRE>
083 * { "filterType" : "and",
084 * "andFilters" : [
085 * { "filterType" : "equals",
086 * "field" : "firstName",
087 * "value" : "John" },
088 * { "filterType" : "equals",
089 * "field" : "lastName",
090 * "value" : "Doe" } ] }
091 * </PRE>
092 * The above filter can be created with the code:
093 * <PRE>
094 * ANDJSONObjectFilter filter = new ANDJSONObjectFilter(
095 * new EqualsJSONObjectFilter("firstName", "John"),
096 * new EqualsJSONObjectFilter("firstName", "Doe"));
097 * </PRE>
098 */
099 @Mutable()
100 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
101 public final class ANDJSONObjectFilter
102 extends JSONObjectFilter
103 {
104 /**
105 * The value that should be used for the filterType element of the JSON object
106 * that represents an "AND" filter.
107 */
108 public static final String FILTER_TYPE = "and";
109
110
111
112 /**
113 * The name of the JSON field that is used to specify the set of filters to
114 * include in this AND filter.
115 */
116 public static final String FIELD_AND_FILTERS = "andFilters";
117
118
119
120 /**
121 * The pre-allocated set of required field names.
122 */
123 private static final Set<String> REQUIRED_FIELD_NAMES =
124 Collections.unmodifiableSet(new HashSet<String>(
125 Collections.singletonList(FIELD_AND_FILTERS)));
126
127
128
129 /**
130 * The pre-allocated set of optional field names.
131 */
132 private static final Set<String> OPTIONAL_FIELD_NAMES =
133 Collections.emptySet();
134
135
136
137 /**
138 * The serial version UID for this serializable class.
139 */
140 private static final long serialVersionUID = 6616759665873968672L;
141
142
143
144 // The set of embedded filters for this AND filter.
145 private volatile List<JSONObjectFilter> andFilters;
146
147
148
149 /**
150 * Creates a new instance of this filter type with the provided information.
151 *
152 * @param andFilters The set of filters that must each match a JSON object
153 * in order for this AND filter to match. If this is
154 * {@code null} or empty, then this AND filter will match
155 * any JSON object.
156 */
157 public ANDJSONObjectFilter(final JSONObjectFilter... andFilters)
158 {
159 this(StaticUtils.toList(andFilters));
160 }
161
162
163
164 /**
165 * Creates a new instance of this filter type with the provided information.
166 *
167 * @param andFilters The set of filters that must each match a JSON object
168 * in order for this AND filter to match. If this is
169 * {@code null} or empty, then this AND filter will match
170 * any JSON object.
171 */
172 public ANDJSONObjectFilter(final Collection<JSONObjectFilter> andFilters)
173 {
174 setANDFilters(andFilters);
175 }
176
177
178
179 /**
180 * Retrieves the set of filters that must each match a JSON object in order
181 * for this AND filter to match.
182 *
183 * @return The set of filters that must each match a JSON object in order for
184 * this AND filter to match, or an empty list if this AND filter
185 * should match any JSON object.
186 */
187 public List<JSONObjectFilter> getANDFilters()
188 {
189 return andFilters;
190 }
191
192
193
194 /**
195 * Specifies the set of AND filters that must each match a JSON object in
196 * order for this AND filter to match.
197 *
198 * @param andFilters The set of filters that must each match a JSON object
199 * in order for this AND filter to match. If this is
200 * {@code null} or empty, then this AND filter will match
201 * any JSON object.
202 */
203 public void setANDFilters(final JSONObjectFilter... andFilters)
204 {
205 setANDFilters(StaticUtils.toList(andFilters));
206 }
207
208
209
210 /**
211 * Specifies the set of AND filters that must each match a JSON object in
212 * order for this AND filter to match.
213 *
214 * @param andFilters The set of filters that must each match a JSON object
215 * in order for this AND filter to match. If this is
216 * {@code null} or empty, then this AND filter will match
217 * any JSON object.
218 */
219 public void setANDFilters(final Collection<JSONObjectFilter> andFilters)
220 {
221 if ((andFilters == null) || andFilters.isEmpty())
222 {
223 this.andFilters = Collections.emptyList();
224 }
225 else
226 {
227 this.andFilters = Collections.unmodifiableList(
228 new ArrayList<JSONObjectFilter>(andFilters));
229 }
230 }
231
232
233
234 /**
235 * {@inheritDoc}
236 */
237 @Override()
238 public String getFilterType()
239 {
240 return FILTER_TYPE;
241 }
242
243
244
245 /**
246 * {@inheritDoc}
247 */
248 @Override()
249 protected Set<String> getRequiredFieldNames()
250 {
251 return REQUIRED_FIELD_NAMES;
252 }
253
254
255
256 /**
257 * {@inheritDoc}
258 */
259 @Override()
260 protected Set<String> getOptionalFieldNames()
261 {
262 return OPTIONAL_FIELD_NAMES;
263 }
264
265
266
267 /**
268 * {@inheritDoc}
269 */
270 @Override()
271 public boolean matchesJSONObject(final JSONObject o)
272 {
273 for (final JSONObjectFilter f : andFilters)
274 {
275 if (! f.matchesJSONObject(o))
276 {
277 return false;
278 }
279 }
280
281 return true;
282 }
283
284
285
286 /**
287 * {@inheritDoc}
288 */
289 @Override()
290 public JSONObject toJSONObject()
291 {
292 final LinkedHashMap<String,JSONValue> fields =
293 new LinkedHashMap<String,JSONValue>(2);
294
295 fields.put(FIELD_FILTER_TYPE, new JSONString(FILTER_TYPE));
296
297 final ArrayList<JSONValue> filterValues =
298 new ArrayList<JSONValue>(andFilters.size());
299 for (final JSONObjectFilter f : andFilters)
300 {
301 filterValues.add(f.toJSONObject());
302 }
303 fields.put(FIELD_AND_FILTERS, new JSONArray(filterValues));
304
305 return new JSONObject(fields);
306 }
307
308
309
310 /**
311 * {@inheritDoc}
312 */
313 @Override()
314 protected ANDJSONObjectFilter decodeFilter(final JSONObject filterObject)
315 throws JSONException
316 {
317 return new ANDJSONObjectFilter(getFilters(filterObject, FIELD_AND_FILTERS));
318 }
319 }