001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.shared.ldap.schema;
021
022
023 import java.util.List;
024
025 import javax.naming.NamingException;
026
027 import org.apache.directory.shared.i18n.I18n;
028 import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
029 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
030 import org.apache.directory.shared.ldap.schema.comparators.ComparableComparator;
031 import org.apache.directory.shared.ldap.schema.normalizers.NoOpNormalizer;
032 import org.apache.directory.shared.ldap.schema.registries.Registries;
033
034
035 /**
036 * A matchingRule definition. MatchingRules associate a comparator and a
037 * normalizer, forming the basic tools necessary to assert actions against
038 * attribute values. MatchingRules are associated with a specific Syntax for the
039 * purpose of resolving a normalized form and for comparisons.
040 * <p>
041 * According to ldapbis [MODELS]:
042 * </p>
043 *
044 * <pre>
045 * 4.1.3. Matching Rules
046 *
047 * Matching rules are used by servers to compare attribute values against
048 * assertion values when performing Search and Compare operations. They
049 * are also used to identify the value to be added or deleted when
050 * modifying entries, and are used when comparing a purported
051 * distinguished name with the name of an entry.
052 *
053 * A matching rule specifies the syntax of the assertion value.
054 *
055 * Each matching rule is identified by an object identifier (OID) and,
056 * optionally, one or more short names (descriptors).
057 *
058 * Matching rule definitions are written according to the ABNF:
059 *
060 * MatchingRuleDescription = LPAREN WSP
061 * numericoid ; object identifier
062 * [ SP "NAME" SP qdescrs ] ; short names (descriptors)
063 * [ SP "DESC" SP qdstring ] ; description
064 * [ SP "OBSOLETE" ] ; not active
065 * SP "SYNTAX" SP numericoid ; assertion syntax
066 * extensions WSP RPAREN ; extensions
067 *
068 * where:
069 * [numericoid] is object identifier assigned to this matching rule;
070 * NAME [qdescrs] are short names (descriptors) identifying this
071 * matching rule;
072 * DESC [qdstring] is a short descriptive string;
073 * OBSOLETE indicates this matching rule is not active;
074 * SYNTAX identifies the assertion syntax by object identifier; and
075 * [extensions] describe extensions.
076 * </pre>
077 *
078 * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 4.5</a>
079 * @see <a
080 * href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
081 * [MODELS]</a>
082 * @see DescriptionUtils#getDescription(MatchingRule)
083 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
084 * @version $Rev: 919765 $
085 */
086 public class MatchingRule extends AbstractSchemaObject
087 {
088 /** The serialVersionUID */
089 private static final long serialVersionUID = 1L;
090
091 /** The associated Comparator */
092 protected LdapComparator<? super Object> ldapComparator;
093
094 /** The associated Normalizer */
095 protected Normalizer normalizer;
096
097 /** The associated LdapSyntax */
098 protected LdapSyntax ldapSyntax;
099
100 /** The associated LdapSyntax OID */
101 private String ldapSyntaxOid;
102
103
104 /**
105 * Creates a new instance of MatchingRule.
106 *
107 * @param oid The MatchingRule OID
108 * @param registries The Registries reference
109 */
110 public MatchingRule( String oid )
111 {
112 super( SchemaObjectType.MATCHING_RULE, oid );
113 }
114
115
116 /**
117 * Inject the MatchingRule into the registries, updating the references to
118 * other SchemaObject
119 *
120 * @param registries The Registries
121 * @exception If the addition failed
122 */
123 public void addToRegistries( List<Throwable> errors, Registries registries ) throws NamingException
124 {
125 if ( registries != null )
126 {
127 try
128 {
129 // Gets the associated Comparator
130 ldapComparator = ( LdapComparator<? super Object> ) registries.getComparatorRegistry().lookup( oid );
131 }
132 catch ( NamingException ne )
133 {
134 // Default to a catch all comparator
135 ldapComparator = new ComparableComparator( oid );
136 }
137
138 try
139 {
140 // Gets the associated Normalizer
141 normalizer = registries.getNormalizerRegistry().lookup( oid );
142 }
143 catch ( NamingException ne )
144 {
145 // Default to the NoOp normalizer
146 normalizer = new NoOpNormalizer( oid );
147 }
148
149 try
150 {
151 // Get the associated LdapSyntax
152 ldapSyntax = registries.getLdapSyntaxRegistry().lookup( ldapSyntaxOid );
153 }
154 catch ( NamingException ne )
155 {
156 // The Syntax is a mandatory element, it must exist.
157 throw new LdapSchemaViolationException( I18n.err( I18n.ERR_04317 ),
158 ResultCodeEnum.UNWILLING_TO_PERFORM );
159 }
160
161 /**
162 * Add the MR references (using and usedBy) :
163 * MR -> C
164 * MR -> N
165 * MR -> S
166 */
167 if ( ldapComparator != null )
168 {
169 registries.addReference( this, ldapComparator );
170 }
171
172 if ( normalizer != null )
173 {
174 registries.addReference( this, normalizer );
175 }
176
177 if ( ldapSyntax != null )
178 {
179 registries.addReference( this, ldapSyntax );
180 }
181
182 }
183 }
184
185
186 /**
187 * Remove the MatchingRule from the registries, updating the references to
188 * other SchemaObject.
189 *
190 * If one of the referenced SchemaObject does not exist (),
191 * an exception is thrown.
192 *
193 * @param registries The Registries
194 * @exception If the MatchingRule is not valid
195 */
196 public void removeFromRegistries( List<Throwable> errors, Registries registries ) throws NamingException
197 {
198 if ( registries != null )
199 {
200 /**
201 * Remove the MR references (using and usedBy) :
202 * MR -> C
203 * MR -> N
204 * MR -> S
205 */
206 if ( ldapComparator != null )
207 {
208 registries.delReference( this, ldapComparator );
209 }
210
211 if ( ldapSyntax != null )
212 {
213 registries.delReference( this, ldapSyntax );
214 }
215
216 if ( normalizer != null )
217 {
218 registries.delReference( this, normalizer );
219 }
220 }
221 }
222
223
224 /**
225 * Gets the LdapSyntax used by this MatchingRule.
226 *
227 * @return the LdapSyntax of this MatchingRule
228 */
229 public LdapSyntax getSyntax()
230 {
231 return ldapSyntax;
232 }
233
234
235 /**
236 * Gets the LdapSyntax OID used by this MatchingRule.
237 *
238 * @return the LdapSyntax of this MatchingRule
239 * @throws NamingException if there is a failure resolving the object
240 */
241 public String getSyntaxOid()
242 {
243 return ldapSyntaxOid;
244 }
245
246
247 /**
248 * Sets the Syntax's OID
249 *
250 * @param oid The Syntax's OID
251 */
252 public void setSyntaxOid( String oid )
253 {
254 if ( !isReadOnly )
255 {
256 this.ldapSyntaxOid = oid;
257 }
258 }
259
260
261 /**
262 * Sets the Syntax
263 *
264 * @param oid The Syntax
265 */
266 public void setSyntax( LdapSyntax ldapSyntax )
267 {
268 if ( !isReadOnly )
269 {
270 this.ldapSyntax = ldapSyntax;
271 this.ldapSyntaxOid = ldapSyntax.getOid();
272 }
273 }
274
275
276 /**
277 * Update the associated Syntax, even if the SchemaObject is readOnly
278 *
279 * @param oid The Syntax
280 */
281 public void updateSyntax( LdapSyntax ldapSyntax )
282 {
283 this.ldapSyntax = ldapSyntax;
284 this.ldapSyntaxOid = ldapSyntax.getOid();
285 }
286
287
288 /**
289 * Gets the LdapComparator enabling the use of this MatchingRule for ORDERING
290 * and sorted indexing.
291 *
292 * @return the ordering LdapComparator
293 * @throws NamingException if there is a failure resolving the object
294 */
295 public LdapComparator<? super Object> getLdapComparator()
296 {
297 return ldapComparator;
298 }
299
300
301 /**
302 * Sets the LdapComparator
303 *
304 * @param oid The LdapComparator
305 */
306 public void setLdapComparator( LdapComparator<?> ldapComparator )
307 {
308 if ( !isReadOnly )
309 {
310 this.ldapComparator = ( LdapComparator<? super Object> ) ldapComparator;
311 }
312 }
313
314
315 /**
316 * Update the associated Comparator, even if the SchemaObject is readOnly
317 *
318 * @param oid The LdapComparator
319 */
320 public void updateLdapComparator( LdapComparator<?> ldapComparator )
321 {
322 this.ldapComparator = ( LdapComparator<? super Object> ) ldapComparator;
323 }
324
325
326 /**
327 * Gets the Normalizer enabling the use of this MatchingRule for EQUALITY
328 * matching and indexing.
329 *
330 * @return the associated normalizer
331 * @throws NamingException if there is a failure resolving the object
332 */
333 public Normalizer getNormalizer()
334 {
335 return normalizer;
336 }
337
338
339 /**
340 * Sets the Normalizer
341 *
342 * @param oid The Normalizer
343 */
344 public void setNormalizer( Normalizer normalizer )
345 {
346 if ( !isReadOnly )
347 {
348 this.normalizer = normalizer;
349 }
350 }
351
352
353 /**
354 * Update the associated Normalizer, even if the SchemaObject is readOnly
355 *
356 * @param oid The Normalizer
357 */
358 public void updateNormalizer( Normalizer normalizer )
359 {
360 this.normalizer = normalizer;
361 }
362
363
364 /**
365 * @see Object#toString()
366 */
367 public String toString()
368 {
369 return objectType + " " + DescriptionUtils.getDescription( this );
370 }
371
372
373 /**
374 * Copy an MatchingRule
375 */
376 public MatchingRule copy()
377 {
378 MatchingRule copy = new MatchingRule( oid );
379
380 // Copy the SchemaObject common data
381 copy.copy( this );
382
383 // All the references to other Registries object are set to null.
384 copy.ldapComparator = null;
385 copy.ldapSyntax = null;
386 copy.normalizer = null;
387
388 // Copy the syntax OID
389 copy.ldapSyntaxOid = ldapSyntaxOid;
390
391 return copy;
392 }
393
394
395 /**
396 * @see Object#equals()
397 */
398 public boolean equals( Object o )
399 {
400 if ( !super.equals( o ) )
401 {
402 return false;
403 }
404
405 if ( !( o instanceof MatchingRule ) )
406 {
407 return false;
408 }
409
410 MatchingRule that = ( MatchingRule ) o;
411
412 // Check the Comparator
413 if ( ldapComparator != null )
414 {
415 if ( !ldapComparator.equals( that.ldapComparator ) )
416 {
417 return false;
418 }
419 }
420 else
421 {
422 if ( that.ldapComparator != null )
423 {
424 return false;
425 }
426 }
427
428 // Check the Normalizer
429 if ( normalizer != null )
430 {
431 if ( !normalizer.equals( that.normalizer ) )
432 {
433 return false;
434 }
435 }
436 else
437 {
438 if ( that.normalizer != null )
439 {
440 return false;
441 }
442 }
443
444 // Check the Syntax
445 if ( !compareOid( ldapSyntaxOid, that.ldapSyntaxOid ) )
446 {
447 return false;
448 }
449
450 return ldapSyntax.equals( that.ldapSyntax );
451 }
452
453
454 /**
455 * {@inheritDoc}
456 */
457 public void clear()
458 {
459 // Clear the common elements
460 super.clear();
461
462 // Clear the references
463 ldapComparator = null;
464 ldapSyntax = null;
465 normalizer = null;
466 }
467 }