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