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 import org.opends.messages.Message; 029 030 031 032 import java.util.List; 033 034 import org.opends.server.admin.std.server.SubstringMatchingRuleCfg; 035 import org.opends.server.api.SubstringMatchingRule; 036 import org.opends.server.config.ConfigException; 037 import org.opends.server.core.DirectoryServer; 038 import org.opends.server.protocols.asn1.ASN1OctetString; 039 import org.opends.server.types.ByteString; 040 import org.opends.server.types.DirectoryException; 041 import org.opends.server.types.InitializationException; 042 import org.opends.server.types.ResultCode; 043 044 import static org.opends.messages.SchemaMessages.*; 045 import static org.opends.server.schema.SchemaConstants.*; 046 import static org.opends.server.util.StaticUtils.*; 047 import org.opends.server.loggers.ErrorLogger; 048 049 050 /** 051 * This class implements the numericStringSubstringsMatch matching rule defined 052 * in X.520 and referenced in RFC 2252. 053 */ 054 public class NumericStringSubstringMatchingRule 055 extends SubstringMatchingRule 056 { 057 /** 058 * Creates a new instance of this numericStringSubstringsMatch matching rule. 059 */ 060 public NumericStringSubstringMatchingRule() 061 { 062 super(); 063 } 064 065 066 067 /** 068 * {@inheritDoc} 069 */ 070 public void initializeMatchingRule(SubstringMatchingRuleCfg configuration) 071 throws ConfigException, InitializationException 072 { 073 // No initialization is required. 074 } 075 076 077 078 /** 079 * Retrieves the common name for this matching rule. 080 * 081 * @return The common name for this matching rule, or <CODE>null</CODE> if 082 * it does not have a name. 083 */ 084 public String getName() 085 { 086 return SMR_NUMERIC_STRING_NAME; 087 } 088 089 090 091 /** 092 * Retrieves the OID for this matching rule. 093 * 094 * @return The OID for this matching rule. 095 */ 096 public String getOID() 097 { 098 return SMR_NUMERIC_STRING_OID; 099 } 100 101 102 103 /** 104 * Retrieves the description for this matching rule. 105 * 106 * @return The description for this matching rule, or <CODE>null</CODE> if 107 * there is none. 108 */ 109 public String getDescription() 110 { 111 // There is no standard description for this matching rule. 112 return null; 113 } 114 115 116 117 /** 118 * Retrieves the OID of the syntax with which this matching rule is 119 * associated. 120 * 121 * @return The OID of the syntax with which this matching rule is associated. 122 */ 123 public String getSyntaxOID() 124 { 125 return SYNTAX_SUBSTRING_ASSERTION_OID; 126 } 127 128 129 130 /** 131 * Retrieves the normalized form of the provided value, which is best suited 132 * for efficiently performing matching operations on that value. 133 * 134 * @param value The value to be normalized. 135 * 136 * @return The normalized version of the provided value. 137 * 138 * @throws DirectoryException If the provided value is invalid according to 139 * the associated attribute syntax. 140 */ 141 public ByteString normalizeValue(ByteString value) 142 throws DirectoryException 143 { 144 String valueString = value.stringValue(); 145 int valueLength = valueString.length(); 146 StringBuilder valueBuffer = new StringBuilder(valueLength); 147 148 boolean logged = false; 149 for (int i=0; i < valueLength; i++) 150 { 151 char c = valueString.charAt(i); 152 if (isDigit(c)) 153 { 154 valueBuffer.append(c); 155 } 156 else if (c != ' ') 157 { 158 // This is an illegal character. Either log it or reject it. 159 160 Message message = WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR.get( 161 valueString, String.valueOf(c), i); 162 163 switch (DirectoryServer.getSyntaxEnforcementPolicy()) 164 { 165 case REJECT: 166 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 167 message); 168 case WARN: 169 if (! logged) 170 { 171 ErrorLogger.logError(message); 172 logged = true; 173 } 174 } 175 } 176 } 177 178 return new ASN1OctetString(getBytes(valueBuffer.toString())); 179 } 180 181 182 183 /** 184 * Normalizes the provided value fragment into a form that can be used to 185 * efficiently compare values. 186 * 187 * @param substring The value fragment to be normalized. 188 * 189 * @return The normalized form of the value fragment. 190 * 191 * @throws DirectoryException If the provided value fragment is not 192 * acceptable according to the associated syntax. 193 */ 194 public ByteString normalizeSubstring(ByteString substring) 195 throws DirectoryException 196 { 197 String valueString = substring.stringValue(); 198 int valueLength = valueString.length(); 199 StringBuilder valueBuffer = new StringBuilder(valueLength); 200 201 boolean logged = false; 202 for (int i=0; i < valueLength; i++) 203 { 204 char c = valueString.charAt(i); 205 if (isDigit(c)) 206 { 207 valueBuffer.append(c); 208 } 209 else if (c != ' ') 210 { 211 // This is an illegal character. Either log it or reject it. 212 213 Message message = WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR.get( 214 valueString, String.valueOf(c), i); 215 216 switch (DirectoryServer.getSyntaxEnforcementPolicy()) 217 { 218 case REJECT: 219 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 220 message); 221 case WARN: 222 if (! logged) 223 { 224 ErrorLogger.logError(message); 225 logged = true; 226 } 227 } 228 } 229 } 230 231 return new ASN1OctetString(getBytes(valueBuffer.toString())); 232 } 233 234 235 236 /** 237 * Determines whether the provided value matches the given substring filter 238 * components. Note that any of the substring filter components may be 239 * <CODE>null</CODE> but at least one of them must be non-<CODE>null</CODE>. 240 * 241 * @param value The normalized value against which to compare the 242 * substring components. 243 * @param subInitial The normalized substring value fragment that should 244 * appear at the beginning of the target value. 245 * @param subAnyElements The normalized substring value fragments that 246 * should appear in the middle of the target value. 247 * @param subFinal The normalized substring value fragment that should 248 * appear at the end of the target value. 249 * 250 * @return <CODE>true</CODE> if the provided value does match the given 251 * substring components, or <CODE>false</CODE> if not. 252 */ 253 public boolean valueMatchesSubstring(ByteString value, ByteString subInitial, 254 List<ByteString> subAnyElements, 255 ByteString subFinal) 256 { 257 byte[] valueBytes = value.value(); 258 int valueLength = valueBytes.length; 259 260 int pos = 0; 261 if (subInitial != null) 262 { 263 byte[] initialBytes = subInitial.value(); 264 int initialLength = initialBytes.length; 265 if (initialLength > valueLength) 266 { 267 return false; 268 } 269 270 for (; pos < initialLength; pos++) 271 { 272 if (initialBytes[pos] != valueBytes[pos]) 273 { 274 return false; 275 } 276 } 277 } 278 279 280 if ((subAnyElements != null) && (! subAnyElements.isEmpty())) 281 { 282 for (ByteString element : subAnyElements) 283 { 284 byte[] anyBytes = element.value(); 285 int anyLength = anyBytes.length; 286 287 int end = valueLength - anyLength; 288 boolean match = false; 289 if (anyLength == 0) 290 { 291 // empty element is not considered as unmatching 292 match = true; 293 continue; 294 } 295 for (; pos <= end; pos++) 296 { 297 if (anyBytes[0] == valueBytes[pos]) 298 { 299 boolean subMatch = true; 300 for (int i=1; i < anyLength; i++) 301 { 302 if (anyBytes[i] != valueBytes[pos+i]) 303 { 304 subMatch = false; 305 break; 306 } 307 } 308 309 if (subMatch) 310 { 311 match = subMatch; 312 break; 313 } 314 } 315 } 316 317 if (match) 318 { 319 pos += anyLength; 320 } 321 else 322 { 323 return false; 324 } 325 } 326 } 327 328 329 if (subFinal != null) 330 { 331 byte[] finalBytes = subFinal.value(); 332 int finalLength = finalBytes.length; 333 334 if ((valueLength - finalLength) < pos) 335 { 336 return false; 337 } 338 339 pos = valueLength - finalLength; 340 for (int i=0; i < finalLength; i++,pos++) 341 { 342 if (finalBytes[i] != valueBytes[pos]) 343 { 344 return false; 345 } 346 } 347 } 348 349 350 return true; 351 } 352 } 353