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.Collections;
026 import java.util.HashSet;
027 import java.util.LinkedHashMap;
028 import java.util.Set;
029
030 import com.unboundid.util.Debug;
031 import com.unboundid.util.Mutable;
032 import com.unboundid.util.ThreadSafety;
033 import com.unboundid.util.ThreadSafetyLevel;
034 import com.unboundid.util.Validator;
035 import com.unboundid.util.json.JSONException;
036 import com.unboundid.util.json.JSONObject;
037 import com.unboundid.util.json.JSONString;
038 import com.unboundid.util.json.JSONValue;
039
040 import static com.unboundid.ldap.sdk.unboundidds.jsonfilter.JFMessages.*;
041
042
043
044 /**
045 * <BLOCKQUOTE>
046 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
047 * LDAP SDK for Java. It is not available for use in applications that
048 * include only the Standard Edition of the LDAP SDK, and is not supported for
049 * use in conjunction with non-UnboundID products.
050 * </BLOCKQUOTE>
051 * This class provides an implementation of a JSON object filter that can
052 * negate the result of a provided filter. If the embedded filter matches a
053 * given JSON object, then this negate filter will not match that object. If
054 * the embedded filter does not match a JSON object, then this negate filter
055 * will match that object.
056 * <BR><BR>
057 * The fields that are required to be included in a "negate" filter are:
058 * <UL>
059 * <LI>
060 * {@code negateFilter} -- The JSON object filter whose match result should
061 * be negated.
062 * </LI>
063 * </UL>
064 * <H2>Example</H2>
065 * The following is an example of a "negate" filter that will match any JSON
066 * object that does not have a top-level field named "userType" with a value of
067 * "employee":
068 * <PRE>
069 * { "filterType" : "negate",
070 * "negateFilter" : {
071 * "filterType" : "equals",
072 * "field" : "userType",
073 * "value" : "employee" } }
074 * </PRE>
075 * The above filter can be created with the code:
076 * <PRE>
077 * NegateJSONObjectFilter filter = new NegateJSONObjectFilter(
078 * new EqualsJSONObjectFilter("userType", "employee"));
079 * </PRE>
080 */
081 @Mutable()
082 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
083 public final class NegateJSONObjectFilter
084 extends JSONObjectFilter
085 {
086 /**
087 * The value that should be used for the filterType element of the JSON object
088 * that represents a "negate" filter.
089 */
090 public static final String FILTER_TYPE = "negate";
091
092
093
094 /**
095 * The name of the JSON field that is used to specify the filter to negate.
096 */
097 public static final String FIELD_NEGATE_FILTER = "negateFilter";
098
099
100
101 /**
102 * The pre-allocated set of required field names.
103 */
104 private static final Set<String> REQUIRED_FIELD_NAMES =
105 Collections.unmodifiableSet(new HashSet<String>(
106 Collections.singletonList(FIELD_NEGATE_FILTER)));
107
108
109
110 /**
111 * The pre-allocated set of optional field names.
112 */
113 private static final Set<String> OPTIONAL_FIELD_NAMES =
114 Collections.emptySet();
115
116
117
118 /**
119 * The serial version UID for this serializable class.
120 */
121 private static final long serialVersionUID = -9067967834329526711L;
122
123
124
125 // The embedded filter whose result will be negated.
126 private volatile JSONObjectFilter negateFilter;
127
128
129
130 /**
131 * Creates an instance of this filter type that can only be used for decoding
132 * JSON objects as "negate" filters. It cannot be used as a regular "negate"
133 * filter.
134 */
135 NegateJSONObjectFilter()
136 {
137 negateFilter = null;
138 }
139
140
141
142 /**
143 * Creates a new instance of this filter type with the provided information.
144 *
145 * @param negateFilter The JSON object filter whose match result should be
146 * negated. It must not be {@code null}.
147 */
148 public NegateJSONObjectFilter(final JSONObjectFilter negateFilter)
149 {
150 Validator.ensureNotNull(negateFilter);
151
152 this.negateFilter = negateFilter;
153 }
154
155
156
157 /**
158 * Retrieves the JSON object filter whose match result will be negated.
159 *
160 * @return The JSON object filter whose match result will be negated.
161 */
162 public JSONObjectFilter getNegateFilter()
163 {
164 return negateFilter;
165 }
166
167
168
169 /**
170 * Specifies the JSON object filter whose match result should be negated.
171 *
172 * @param negateFilter The JSON object filter whose match result should be
173 * negated.
174 */
175 public void setNegateFilter(final JSONObjectFilter negateFilter)
176 {
177 Validator.ensureNotNull(negateFilter);
178
179 this.negateFilter = negateFilter;
180 }
181
182
183
184 /**
185 * {@inheritDoc}
186 */
187 @Override()
188 public String getFilterType()
189 {
190 return FILTER_TYPE;
191 }
192
193
194
195 /**
196 * {@inheritDoc}
197 */
198 @Override()
199 protected Set<String> getRequiredFieldNames()
200 {
201 return REQUIRED_FIELD_NAMES;
202 }
203
204
205
206 /**
207 * {@inheritDoc}
208 */
209 @Override()
210 protected Set<String> getOptionalFieldNames()
211 {
212 return OPTIONAL_FIELD_NAMES;
213 }
214
215
216
217 /**
218 * {@inheritDoc}
219 */
220 @Override()
221 public boolean matchesJSONObject(final JSONObject o)
222 {
223 return (! negateFilter.matchesJSONObject(o));
224 }
225
226
227
228 /**
229 * {@inheritDoc}
230 */
231 @Override()
232 public JSONObject toJSONObject()
233 {
234 final LinkedHashMap<String,JSONValue> fields =
235 new LinkedHashMap<String,JSONValue>(2);
236
237 fields.put(FIELD_FILTER_TYPE, new JSONString(FILTER_TYPE));
238 fields.put(FIELD_NEGATE_FILTER, negateFilter.toJSONObject());
239
240 return new JSONObject(fields);
241 }
242
243
244
245 /**
246 * {@inheritDoc}
247 */
248 @Override()
249 protected NegateJSONObjectFilter decodeFilter(final JSONObject filterObject)
250 throws JSONException
251 {
252 final JSONValue v = filterObject.getField(FIELD_NEGATE_FILTER);
253 if (v == null)
254 {
255 throw new JSONException(ERR_OBJECT_FILTER_MISSING_REQUIRED_FIELD.get(
256 String.valueOf(filterObject), FILTER_TYPE, FIELD_NEGATE_FILTER));
257 }
258
259 if (! (v instanceof JSONObject))
260 {
261 throw new JSONException(ERR_OBJECT_FILTER_VALUE_NOT_OBJECT.get(
262 String.valueOf(filterObject), FILTER_TYPE, FIELD_NEGATE_FILTER));
263 }
264
265 try
266 {
267 return new NegateJSONObjectFilter(
268 JSONObjectFilter.decode((JSONObject) v));
269 }
270 catch (final JSONException e)
271 {
272 Debug.debugException(e);
273 throw new JSONException(
274 ERR_OBJECT_FILTER_VALUE_NOT_FILTER.get(String.valueOf(filterObject),
275 FILTER_TYPE, FIELD_NEGATE_FILTER, e.getMessage()),
276 e);
277 }
278 }
279 }