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 }