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