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 }