001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.schema;
028
029
030
031 import org.opends.server.admin.std.server.EqualityMatchingRuleCfg;
032 import org.opends.server.api.EqualityMatchingRule;
033 import org.opends.server.config.ConfigException;
034 import org.opends.server.protocols.asn1.ASN1OctetString;
035 import org.opends.server.types.AttributeValue;
036 import org.opends.server.types.ByteString;
037 import org.opends.server.types.DirectoryException;
038 import org.opends.server.types.InitializationException;
039
040 import static org.opends.server.schema.SchemaConstants.*;
041 import static org.opends.server.util.StaticUtils.*;
042
043
044
045 /**
046 * This class implements the wordMatch matching rule defined in X.520. That
047 * document defines "word" as implementation-specific, but in this case we will
048 * consider it a match if the assertion value is contained within the attribute
049 * value and is bounded by the edge of the value or any of the following
050 * characters:
051 * <BR>
052 * <UL>
053 * <LI>A space</LI>
054 * <LI>A period</LI>
055 * <LI>A comma</LI>
056 * <LI>A slash</LI>
057 * <LI>A dollar sign</LI>
058 * <LI>A plus sign</LI>
059 * <LI>A dash</LI>
060 * <LI>An underscore</LI>
061 * <LI>An octothorpe</LI>
062 * <LI>An equal sign</LI>
063 * </UL>
064 */
065 public class WordEqualityMatchingRule
066 extends EqualityMatchingRule
067 {
068 /**
069 * Creates a new instance of this wordMatch matching rule.
070 */
071 public WordEqualityMatchingRule()
072 {
073 super();
074 }
075
076
077
078 /**
079 * {@inheritDoc}
080 */
081 public void initializeMatchingRule(EqualityMatchingRuleCfg configuration)
082 throws ConfigException, InitializationException
083 {
084 // No initialization is required.
085 }
086
087
088
089 /**
090 * Retrieves the common name for this matching rule.
091 *
092 * @return The common name for this matching rule, or <CODE>null</CODE> if
093 * it does not have a name.
094 */
095 public String getName()
096 {
097 return EMR_WORD_NAME;
098 }
099
100
101
102 /**
103 * Retrieves the OID for this matching rule.
104 *
105 * @return The OID for this matching rule.
106 */
107 public String getOID()
108 {
109 return EMR_WORD_OID;
110 }
111
112
113
114 /**
115 * Retrieves the description for this matching rule.
116 *
117 * @return The description for this matching rule, or <CODE>null</CODE> if
118 * there is none.
119 */
120 public String getDescription()
121 {
122 // There is no standard description for this matching rule.
123 return null;
124 }
125
126
127
128 /**
129 * Retrieves the OID of the syntax with which this matching rule is
130 * associated.
131 *
132 * @return The OID of the syntax with which this matching rule is associated.
133 */
134 public String getSyntaxOID()
135 {
136 return SYNTAX_DIRECTORY_STRING_OID;
137 }
138
139
140
141 /**
142 * Retrieves the normalized form of the provided value, which is best suited
143 * for efficiently performing matching operations on that value.
144 *
145 * @param value The value to be normalized.
146 *
147 * @return The normalized version of the provided value.
148 *
149 * @throws DirectoryException If the provided value is invalid according to
150 * the associated attribute syntax.
151 */
152 public ByteString normalizeValue(ByteString value)
153 throws DirectoryException
154 {
155 StringBuilder buffer = new StringBuilder();
156 toLowerCase(value.value(), buffer, true);
157
158 int bufferLength = buffer.length();
159 if (bufferLength == 0)
160 {
161 if (value.value().length > 0)
162 {
163 // This should only happen if the value is composed entirely of spaces.
164 // In that case, the normalized value is a single space.
165 return new ASN1OctetString(" ");
166 }
167 else
168 {
169 // The value is empty, so it is already normalized.
170 return new ASN1OctetString();
171 }
172 }
173
174
175 // Replace any consecutive spaces with a single space.
176 for (int pos = bufferLength-1; pos > 0; pos--)
177 {
178 if (buffer.charAt(pos) == ' ')
179 {
180 if (buffer.charAt(pos-1) == ' ')
181 {
182 buffer.delete(pos, pos+1);
183 }
184 }
185 }
186
187 return new ASN1OctetString(buffer.toString());
188 }
189
190
191
192 /**
193 * Indicates whether the two provided normalized values are equal to each
194 * other.
195 *
196 * @param value1 The normalized form of the first value to compare.
197 * @param value2 The normalized form of the second value to compare.
198 *
199 * @return <CODE>true</CODE> if the provided values are equal, or
200 * <CODE>false</CODE> if not.
201 */
202 public boolean areEqual(ByteString value1, ByteString value2)
203 {
204 // For this purpose, the first value will be considered the attribute value,
205 // and the second the assertion value. See if the second value is contained
206 // in the first. If not, then it isn't a match.
207 String valueStr1 = value1.stringValue();
208 String valueStr2 = value2.stringValue();
209 int pos = valueStr1.indexOf(valueStr2);
210 if (pos < 0)
211 {
212 return false;
213 }
214
215
216 if (pos > 0)
217 {
218 char c = valueStr1.charAt(pos-1);
219 switch (c)
220 {
221 case ' ':
222 case '.':
223 case ',':
224 case '/':
225 case '$':
226 case '+':
227 case '-':
228 case '_':
229 case '#':
230 case '=':
231 // These are all acceptable.
232 break;
233
234 default:
235 // Anything else is not.
236 return false;
237 }
238 }
239
240
241 if (valueStr1.length() > (pos + valueStr2.length()))
242 {
243 char c = valueStr1.charAt(pos + valueStr2.length());
244 switch (c)
245 {
246 case ' ':
247 case '.':
248 case ',':
249 case '/':
250 case '$':
251 case '+':
252 case '-':
253 case '_':
254 case '#':
255 case '=':
256 // These are all acceptable.
257 break;
258
259 default:
260 // Anything else is not.
261 return false;
262 }
263 }
264
265
266 // If we've gotten here, then we can assume it is a match.
267 return true;
268 }
269
270
271
272 /**
273 * Generates a hash code for the provided attribute value. This version of
274 * the method will simply create a hash code from the normalized form of the
275 * attribute value. For matching rules explicitly designed to work in cases
276 * where byte-for-byte comparisons of normalized values is not sufficient for
277 * determining equality (e.g., if the associated attribute syntax is based on
278 * hashed or encrypted values), then this method must be overridden to provide
279 * an appropriate implementation for that case.
280 *
281 * @param attributeValue The attribute value for which to generate the hash
282 * code.
283 *
284 * @return The hash code generated for the provided attribute value.*/
285 public int generateHashCode(AttributeValue attributeValue)
286 {
287 // In this case, we'll always return the same value because the matching
288 // isn't based on the entire value.
289 return 1;
290 }
291 }
292