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 import org.opends.messages.MessageBuilder;
030
031
032 import java.util.Arrays;
033
034 import org.opends.server.admin.std.server.EqualityMatchingRuleCfg;
035 import org.opends.server.api.EqualityMatchingRule;
036 import org.opends.server.api.MatchingRule;
037 import org.opends.server.config.ConfigException;
038 import org.opends.server.core.DirectoryServer;
039 import org.opends.server.protocols.asn1.ASN1OctetString;
040 import org.opends.server.types. AttributeType;
041 import org.opends.server.types.ByteString;
042 import org.opends.server.types.DirectoryException;
043 import org.opends.server.types.InitializationException;
044 import org.opends.server.types.NameForm;
045 import org.opends.server.types.ObjectClass;
046 import org.opends.server.types.ResultCode;
047
048 import static org.opends.messages.SchemaMessages.*;
049 import static org.opends.server.schema.SchemaConstants.*;
050 import static org.opends.server.util.StaticUtils.*;
051 import org.opends.server.loggers.ErrorLogger;
052
053
054 /**
055 * This class defines the objectIdentifierMatch matching rule defined in X.520
056 * and referenced in RFC 2252. This expects to work on OIDs and will match
057 * either an attribute/objectclass name or a numeric OID.
058 */
059 public class ObjectIdentifierEqualityMatchingRule
060 extends EqualityMatchingRule
061 {
062 /**
063 * Creates a new instance of this objectIdentifierMatch matching rule.
064 */
065 public ObjectIdentifierEqualityMatchingRule()
066 {
067 super();
068 }
069
070
071
072 /**
073 * {@inheritDoc}
074 */
075 public void initializeMatchingRule(EqualityMatchingRuleCfg configuration)
076 throws ConfigException, InitializationException
077 {
078 // No initialization is required.
079 }
080
081
082
083 /**
084 * Retrieves the common name for this matching rule.
085 *
086 * @return The common name for this matching rule, or <CODE>null</CODE> if
087 * it does not have a name.
088 */
089 public String getName()
090 {
091 return EMR_OID_NAME;
092 }
093
094
095
096 /**
097 * Retrieves the OID for this matching rule.
098 *
099 * @return The OID for this matching rule.
100 */
101 public String getOID()
102 {
103 return EMR_OID_OID;
104 }
105
106
107
108 /**
109 * Retrieves the description for this matching rule.
110 *
111 * @return The description for this matching rule, or <CODE>null</CODE> if
112 * there is none.
113 */
114 public String getDescription()
115 {
116 // There is no standard description for this matching rule.
117 return null;
118 }
119
120
121
122 /**
123 * Retrieves the OID of the syntax with which this matching rule is
124 * associated.
125 *
126 * @return The OID of the syntax with which this matching rule is associated.
127 */
128 public String getSyntaxOID()
129 {
130 return SYNTAX_OID_OID;
131 }
132
133
134
135 /**
136 * Retrieves the normalized form of the provided value, which is best suited
137 * for efficiently performing matching operations on that value.
138 *
139 * @param value The value to be normalized.
140 *
141 * @return The normalized version of the provided value.
142 *
143 * @throws DirectoryException If the provided value is invalid according to
144 * the associated attribute syntax.
145 */
146 public ByteString normalizeValue(ByteString value)
147 throws DirectoryException
148 {
149 StringBuilder buffer = new StringBuilder();
150 toLowerCase(value.value(), buffer, true);
151 String lowerValue = buffer.toString();
152
153 // Normalize OIDs into schema names, and secondary schema names into
154 // primary schema names.
155
156 String schemaName = null;
157
158 AttributeType attributeType = DirectoryServer.getAttributeType(lowerValue);
159 if (attributeType != null)
160 {
161 schemaName = attributeType.getNameOrOID();
162 }
163
164 if (schemaName == null)
165 {
166 ObjectClass objectClass = DirectoryServer.getObjectClass(lowerValue);
167 if (objectClass != null)
168 {
169 schemaName = objectClass.getNameOrOID();
170 }
171 }
172
173 if (schemaName == null)
174 {
175 MatchingRule matchingRule = DirectoryServer.getMatchingRule(lowerValue);
176 if (matchingRule != null)
177 {
178 schemaName = matchingRule.getNameOrOID();
179 }
180 }
181
182 if (schemaName == null)
183 {
184 NameForm nameForm = DirectoryServer.getNameForm(lowerValue);
185 if (nameForm != null)
186 {
187 schemaName = nameForm.getNameOrOID();
188 }
189 }
190
191 if (schemaName != null)
192 {
193 return new ASN1OctetString(toLowerCase(schemaName));
194 }
195
196 // There were no schema matches so we must check the syntax.
197 switch (DirectoryServer.getSyntaxEnforcementPolicy())
198 {
199 case REJECT:
200 MessageBuilder invalidReason = new MessageBuilder();
201 if (isValidSchemaElement(lowerValue, 0, lowerValue.length(),
202 invalidReason))
203 {
204 return new ASN1OctetString(lowerValue);
205 }
206 else
207 {
208 Message message = ERR_ATTR_SYNTAX_OID_INVALID_VALUE.get(
209 lowerValue, invalidReason.toString());
210 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
211 message);
212 }
213
214 case WARN:
215 invalidReason = new MessageBuilder();
216 if (! isValidSchemaElement(lowerValue, 0, lowerValue.length(),
217 invalidReason))
218 {
219 Message message = ERR_ATTR_SYNTAX_OID_INVALID_VALUE.get(
220 lowerValue, invalidReason.toString());
221 ErrorLogger.logError(message);
222 }
223
224 return new ASN1OctetString(lowerValue);
225
226 default:
227 return new ASN1OctetString(lowerValue);
228 }
229 }
230
231
232
233 /**
234 * Indicates whether the two provided normalized values are equal to each
235 * other.
236 *
237 * @param value1 The normalized form of the first value to compare.
238 * @param value2 The normalized form of the second value to compare.
239 *
240 * @return <CODE>true</CODE> if the provided values are equal, or
241 * <CODE>false</CODE> if not.
242 */
243 public boolean areEqual(ByteString value1, ByteString value2)
244 {
245 // First, compare the normalized values to see if they are the same.
246 if (Arrays.equals(value1.value(), value2.value()))
247 {
248 return true;
249 }
250
251
252 // The following code implies that the normalized values cannot be
253 // compared byte-for-byte, which would require that the generateHashCode
254 // method of EqualityMatchingRule be overridden to avoid using the
255 // normalized value. Instead, values are now normalized such that they
256 // can be compared byte-for-byte. There are still some rare cases where
257 // comparison fails. For example, say there is an object class with primary
258 // name "a" and secondary name "b", and there is also an attribute type with
259 // primary name "b". In this case comparing "a" with "b" returns false even
260 // though the two values are equivalent in an object class context.
261
262 /*
263 // It is possible that they are different names referring to the same
264 // schema element. See if we can find a case where that is true in the
265 // server configuration for all of the following schema element types:
266 // - Attribute Types
267 // - Objectclasses
268 // - Attribute syntaxes
269 // - Matching Rules
270 // - Name Forms
271 String valueStr1 = value1.stringValue();
272 AttributeType attrType1 = DirectoryServer.getAttributeType(valueStr1);
273 if (attrType1 != null)
274 {
275 String valueStr2 = value2.stringValue();
276 AttributeType attrType2 = DirectoryServer.getAttributeType(valueStr2);
277 if (attrType2 == null)
278 {
279 return false;
280 }
281 else
282 {
283 return attrType1.equals(attrType2);
284 }
285 }
286
287 ObjectClass oc1 = DirectoryServer.getObjectClass(valueStr1);
288 if (oc1 != null)
289 {
290 String valueStr2 = value2.stringValue();
291 ObjectClass oc2 = DirectoryServer.getObjectClass(valueStr2);
292 if (oc2 == null)
293 {
294 return false;
295 }
296 else
297 {
298 return oc1.equals(oc2);
299 }
300 }
301
302 AttributeSyntax syntax1 = DirectoryServer.getAttributeSyntax(valueStr1,
303 false);
304 if (syntax1 != null)
305 {
306 String valueStr2 = value2.stringValue();
307 AttributeSyntax syntax2 = DirectoryServer.getAttributeSyntax(valueStr2,
308 false);
309 if (syntax2 == null)
310 {
311 return false;
312 }
313 else
314 {
315 return syntax1.equals(syntax2);
316 }
317 }
318
319
320 MatchingRule mr1 = DirectoryServer.getMatchingRule(valueStr1);
321 if (mr1 != null)
322 {
323 String valueStr2 = value2.stringValue();
324 MatchingRule mr2 = DirectoryServer.getMatchingRule(valueStr2);
325 if (mr2 == null)
326 {
327 return false;
328 }
329 else
330 {
331 return mr1.equals(mr2);
332 }
333 }
334
335
336 NameForm nf1 = DirectoryServer.getNameForm(valueStr1);
337 if (nf1 != null)
338 {
339 String valueStr2 = value2.stringValue();
340 NameForm nf2 = DirectoryServer.getNameForm(valueStr2);
341 if (nf2 == null)
342 {
343 return false;
344 }
345 else
346 {
347 return nf1.equals(nf2);
348 }
349 }
350 */
351
352
353 // If we've gotten here, then we've exhausted all reasonable checking and
354 // we can't consider them equal.
355 return false;
356 }
357
358 }
359