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