001 /*
002 * Copyright 2009-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.examples;
022
023
024
025 import java.io.Serializable;
026 import java.util.Arrays;
027 import java.util.TreeSet;
028
029 import com.unboundid.ldap.sdk.Filter;
030 import com.unboundid.util.NotMutable;
031 import com.unboundid.util.ThreadSafety;
032 import com.unboundid.util.ThreadSafetyLevel;
033
034 import static com.unboundid.util.StaticUtils.*;
035
036
037
038 /**
039 * <BLOCKQUOTE>
040 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
041 * LDAP SDK for Java. It is not available for use in applications that
042 * include only the Standard Edition of the LDAP SDK, and is not supported for
043 * use in conjunction with non-UnboundID products.
044 * </BLOCKQUOTE>
045 * This class provides a data structure for representing search filters in a
046 * generic way. This includes:
047 * <UL>
048 * <LI>Using a consistent order for AND and OR components.</LI>
049 * <LI>Converting all attribute names to lowercase.</LI>
050 * <LI>Replacing the assertion value with a "?" character for equality,
051 * greater-or-equal, less-or-equal, approximate match, and extensible
052 * match filters.</LI>
053 * <LI>Replacing all subInitial, subAny, and subFinal elements with "?"
054 * characters in substring filters.</LI>
055 * </UL>
056 */
057 @NotMutable()
058 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
059 public final class GenericFilter
060 implements Serializable
061 {
062 /**
063 * The serial version UID for this serializable class.
064 */
065 private static final long serialVersionUID = -7875317078624475546L;
066
067
068
069 // The hash code for this generic filter.
070 private final int hashCode;
071
072 // The string representation for this filter.
073 private final String filterString;
074
075
076
077 /**
078 * Creates a new generic filter from the provided search filter.
079 *
080 * @param f The filter to use to create a generic filte.r
081 */
082 public GenericFilter(final Filter f)
083 {
084 final StringBuilder b = new StringBuilder();
085 b.append('(');
086
087 switch (f.getFilterType())
088 {
089 case Filter.FILTER_TYPE_AND:
090 case Filter.FILTER_TYPE_OR:
091 appendComponents(f, b);
092 break;
093
094 case Filter.FILTER_TYPE_NOT:
095 b.append('!');
096 b.append(new GenericFilter(f.getNOTComponent()).toString());
097 break;
098
099 case Filter.FILTER_TYPE_EQUALITY:
100 b.append(toLowerCase(f.getAttributeName()));
101 b.append("=?");
102 break;
103
104 case Filter.FILTER_TYPE_SUBSTRING:
105 b.append(toLowerCase(f.getAttributeName()));
106 b.append('=');
107 if (f.getRawSubInitialValue() != null)
108 {
109 b.append('?');
110 }
111 for (int i=0; i < f.getRawSubAnyValues().length; i++)
112 {
113 b.append("*?");
114 }
115 b.append('*');
116 if (f.getRawSubFinalValue() != null)
117 {
118 b.append('?');
119 }
120 break;
121
122 case Filter.FILTER_TYPE_GREATER_OR_EQUAL:
123 b.append(toLowerCase(f.getAttributeName()));
124 b.append(">=?");
125 break;
126
127 case Filter.FILTER_TYPE_LESS_OR_EQUAL:
128 b.append(toLowerCase(f.getAttributeName()));
129 b.append("<=?");
130 break;
131
132 case Filter.FILTER_TYPE_PRESENCE:
133 b.append(toLowerCase(f.getAttributeName()));
134 b.append("=*");
135 break;
136
137 case Filter.FILTER_TYPE_APPROXIMATE_MATCH:
138 b.append(toLowerCase(f.getAttributeName()));
139 b.append("~=?");
140 break;
141
142 case Filter.FILTER_TYPE_EXTENSIBLE_MATCH:
143 final String attrName = toLowerCase(f.getAttributeName());
144 final String mrID = toLowerCase(f.getMatchingRuleID());
145 if (attrName != null)
146 {
147 b.append(attrName);
148 }
149 if (f.getDNAttributes())
150 {
151 b.append(":dn");
152 }
153 if (mrID != null)
154 {
155 b.append(':');
156 b.append(mrID);
157 }
158 b.append(":=?");
159 break;
160 }
161
162 b.append(')');
163
164 filterString = b.toString();
165 hashCode = filterString.hashCode();
166 }
167
168
169
170 /**
171 * Appends a string representation of the provided AND or OR filter to the
172 * given buffer.
173 *
174 * @param f The filter for which to provide the string representation.
175 * @param b The buffer to which to append the string representation.
176 */
177 private static void appendComponents(final Filter f, final StringBuilder b)
178 {
179 if (f.getFilterType() == Filter.FILTER_TYPE_AND)
180 {
181 b.append('&');
182 }
183 else
184 {
185 b.append('|');
186 }
187
188 final TreeSet<Filter> compSet =
189 new TreeSet<Filter>(FilterComparator.getInstance());
190 compSet.addAll(Arrays.asList(f.getComponents()));
191 for (final Filter fc : compSet)
192 {
193 b.append(new GenericFilter(fc).toString());
194 }
195 }
196
197
198
199 /**
200 * Retrieves a hash code for this generic filter.
201 *
202 * @return A hash code for this generic filter.
203 */
204 @Override()
205 public int hashCode()
206 {
207 return hashCode;
208 }
209
210
211
212 /**
213 * Indicates whether the provided object is equal to this generic filter.
214 *
215 * @param o The object for which to make the determination.
216 *
217 * @return {@code true} the provided object is equal to this generic filter,
218 * or {@code false} if not.
219 */
220 @Override()
221 public boolean equals(final Object o)
222 {
223 if (o == null)
224 {
225 return false;
226 }
227
228 if (o == this)
229 {
230 return true;
231 }
232
233 return ((o instanceof GenericFilter) &&
234 filterString.equals(((GenericFilter) o).filterString));
235 }
236
237
238
239 /**
240 * Retrieves a string representation of this generic filter.
241 *
242 * @return A string representation of this generic filter.
243 */
244 @Override()
245 public String toString()
246 {
247 return filterString;
248 }
249 }