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 }