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