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.server.core.api.schema.registries.synchronizers; 021 022 023import java.util.ArrayList; 024import java.util.List; 025 026import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants; 027import org.apache.directory.api.ldap.model.constants.SchemaConstants; 028import org.apache.directory.api.ldap.model.entry.Entry; 029import org.apache.directory.api.ldap.model.exception.LdapException; 030import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; 031import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException; 032import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException; 033import org.apache.directory.api.ldap.model.message.ResultCodeEnum; 034import org.apache.directory.api.ldap.model.name.Dn; 035import org.apache.directory.api.ldap.model.name.Rdn; 036import org.apache.directory.api.ldap.model.schema.LdapComparator; 037import org.apache.directory.api.ldap.model.schema.SchemaManager; 038import org.apache.directory.api.ldap.model.schema.registries.Schema; 039import org.apache.directory.api.util.Strings; 040import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext; 041import org.apache.directory.server.i18n.I18n; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045 046/** 047 * A handler for operations performed to add, delete, modify, rename and 048 * move schema comparators. 049 * 050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 051 */ 052public class ComparatorSynchronizer extends AbstractRegistrySynchronizer 053{ 054 /** A logger for this class */ 055 private static final Logger LOG = LoggerFactory.getLogger( ComparatorSynchronizer.class ); 056 057 058 /** 059 * Creates a new instance of ComparatorSynchronizer. 060 * 061 * @param schemaManager The global schemaManager 062 * @throws Exception If the initialization failed 063 */ 064 public ComparatorSynchronizer( SchemaManager schemaManager ) throws Exception 065 { 066 super( schemaManager ); 067 } 068 069 070 /** 071 * {@inheritDoc} 072 */ 073 @Override 074 public boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean cascade ) 075 throws LdapException 076 { 077 Dn name = modifyContext.getDn(); 078 Entry entry = modifyContext.getEntry(); 079 String schemaName = getSchemaName( name ); 080 String oid = getOid( entry ); 081 LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, targetEntry, schemaManager 082 .getRegistries(), schemaName ); 083 084 if ( isSchemaEnabled( schemaName ) ) 085 { 086 comparator.setSchemaName( schemaName ); 087 088 schemaManager.unregisterComparator( oid ); 089 schemaManager.add( comparator ); 090 091 return SCHEMA_MODIFIED; 092 } 093 094 return SCHEMA_UNCHANGED; 095 } 096 097 098 /** 099 * {@inheritDoc} 100 */ 101 @Override 102 public void add( Entry entry ) throws LdapException 103 { 104 Dn dn = entry.getDn(); 105 Dn parentDn = dn.getParent(); 106 107 // The parent Dn must be ou=comparators,cn=<schemaName>,ou=schema 108 checkParent( parentDn, schemaManager, SchemaConstants.COMPARATOR ); 109 110 // The new schemaObject's OID must not already exist 111 checkOidIsUniqueForComparator( entry ); 112 113 // Build the new Comparator from the given entry 114 String schemaName = getSchemaName( dn ); 115 116 LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(), 117 schemaName ); 118 119 // At this point, the constructed LdapComparator has not been checked against the 120 // existing Registries. It will be checked there, if the schema and the 121 // LdapComparator are both enabled. 122 Schema schema = schemaManager.getLoadedSchema( schemaName ); 123 124 if ( schema.isEnabled() && comparator.isEnabled() ) 125 { 126 if ( schemaManager.add( comparator ) ) 127 { 128 LOG.debug( "Added {} into the enabled schema {}", dn.getName(), schemaName ); 129 } 130 else 131 { 132 // We have some error : reject the addition and get out 133 String msg = I18n.err( I18n.ERR_350, entry.getDn().getName(), Strings.listToString( 134 schemaManager.getErrors() ) ); 135 LOG.info( msg ); 136 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 137 } 138 } 139 else 140 { 141 LOG.debug( "The Comparator {} cannot be added in the disabled schema {}", dn.getName(), schemaName ); 142 } 143 } 144 145 146 /** 147 * {@inheritDoc} 148 */ 149 @Override 150 public void delete( Entry entry, boolean cascade ) throws LdapException 151 { 152 Dn dn = entry.getDn(); 153 Dn parentDn = dn.getParent(); 154 155 // The parent Dn must be ou=comparators,cn=<schemaName>,ou=schema 156 checkParent( parentDn, schemaManager, SchemaConstants.COMPARATOR ); 157 158 // Get the SchemaName 159 String schemaName = getSchemaName( entry.getDn() ); 160 161 // Get the Schema 162 Schema schema = schemaManager.getLoadedSchema( schemaName ); 163 164 if ( schema.isDisabled() ) 165 { 166 // The schema is disabled, nothing to do. 167 LOG.debug( "The Comparator {} cannot be deleted from the disabled schema {}", dn.getName(), schemaName ); 168 169 return; 170 } 171 172 // Test that the Oid exists 173 LdapComparator<?> comparator = null; 174 175 try 176 { 177 comparator = checkComparatorOidExists( entry ); 178 } 179 catch ( LdapSchemaViolationException lsve ) 180 { 181 // The comparator does not exist 182 comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(), schemaName ); 183 184 if ( schemaManager.getRegistries().contains( comparator ) ) 185 { 186 // Remove the Comparator from the schema/SchemaObject Map 187 schemaManager.getRegistries().dissociateFromSchema( comparator ); 188 189 // Ok, we can exit. 190 return; 191 } 192 else 193 { 194 // Ok, definitively an error 195 String msg = I18n.err( I18n.ERR_351, entry.getDn().getName() ); 196 LOG.info( msg ); 197 throw new LdapSchemaViolationException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 198 } 199 } 200 201 List<Throwable> errors = new ArrayList<>(); 202 203 if ( schema.isEnabled() && comparator.isEnabled() ) 204 { 205 if ( schemaManager.delete( comparator ) ) 206 { 207 LOG.debug( "Deleted {} from the enabled schema {}", dn.getName(), schemaName ); 208 } 209 else 210 { 211 String msg = I18n.err( I18n.ERR_352, entry.getDn().getName(), Strings.listToString( 212 errors ) ); 213 LOG.info( msg ); 214 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 215 } 216 } 217 else 218 { 219 LOG.debug( "The Comparator {} cannot be deleted from the disabled schema {}", dn.getName(), schemaName ); 220 } 221 } 222 223 224 /** 225 * {@inheritDoc} 226 */ 227 @Override 228 public void rename( Entry entry, Rdn newRdn, boolean cascade ) throws LdapException 229 { 230 String oldOid = getOid( entry ); 231 232 if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) ) 233 { 234 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, 235 I18n.err( I18n.ERR_353, oldOid ) ); 236 } 237 238 String oid = newRdn.getValue(); 239 checkOidIsUniqueForComparator( oid ); 240 241 String schemaName = getSchemaName( entry.getDn() ); 242 243 if ( isSchemaEnabled( schemaName ) ) 244 { 245 // Inject the new OID in the entry 246 Entry targetEntry = entry.clone(); 247 String newOid = newRdn.getValue(); 248 checkOidIsUnique( newOid ); 249 targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid ); 250 251 // Inject the new Dn 252 Dn newDn = targetEntry.getDn().getParent(); 253 newDn = newDn.add( newRdn ); 254 targetEntry.setDn( newDn ); 255 256 // Register the new comparator, and unregister the old one 257 LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, targetEntry, schemaManager 258 .getRegistries(), schemaName ); 259 schemaManager.unregisterComparator( oldOid ); 260 schemaManager.add( comparator ); 261 } 262 } 263 264 265 /** 266 * {@inheritDoc} 267 */ 268 @Override 269 public void moveAndRename( Dn oriChildName, Dn newParentName, Rdn newRdn, boolean deleteOldRn, 270 Entry entry, boolean cascade ) throws LdapException 271 { 272 checkNewParent( newParentName ); 273 String oldOid = getOid( entry ); 274 275 if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) ) 276 { 277 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, 278 I18n.err( I18n.ERR_353, oldOid ) ); 279 } 280 281 String oid = newRdn.getValue(); 282 checkOidIsUniqueForComparator( oid ); 283 284 String newSchemaName = getSchemaName( newParentName ); 285 286 LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(), 287 newSchemaName ); 288 289 String oldSchemaName = getSchemaName( oriChildName ); 290 291 if ( isSchemaEnabled( oldSchemaName ) ) 292 { 293 schemaManager.unregisterComparator( oldOid ); 294 } 295 296 if ( isSchemaEnabled( newSchemaName ) ) 297 { 298 schemaManager.add( comparator ); 299 } 300 } 301 302 303 /** 304 * {@inheritDoc} 305 */ 306 @Override 307 public void move( Dn oriChildName, Dn newParentName, Entry entry, boolean cascade ) throws LdapException 308 { 309 checkNewParent( newParentName ); 310 String oid = getOid( entry ); 311 312 if ( schemaManager.getMatchingRuleRegistry().contains( oid ) ) 313 { 314 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, 315 I18n.err( I18n.ERR_354, oid ) ); 316 } 317 318 String newSchemaName = getSchemaName( newParentName ); 319 320 LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(), 321 newSchemaName ); 322 323 String oldSchemaName = getSchemaName( oriChildName ); 324 325 if ( isSchemaEnabled( oldSchemaName ) ) 326 { 327 schemaManager.unregisterComparator( oid ); 328 } 329 330 if ( isSchemaEnabled( newSchemaName ) ) 331 { 332 schemaManager.add( comparator ); 333 } 334 } 335 336 337 private void checkOidIsUniqueForComparator( String oid ) throws LdapSchemaViolationException 338 { 339 if ( schemaManager.getComparatorRegistry().contains( oid ) ) 340 { 341 throw new LdapSchemaViolationException( ResultCodeEnum.OTHER, 342 I18n.err( I18n.ERR_355, oid ) ); 343 } 344 } 345 346 347 private void checkOidIsUniqueForComparator( Entry entry ) throws LdapException 348 { 349 String oid = getOid( entry ); 350 351 if ( schemaManager.getComparatorRegistry().contains( oid ) ) 352 { 353 throw new LdapSchemaViolationException( ResultCodeEnum.OTHER, 354 I18n.err( I18n.ERR_355, oid ) ); 355 } 356 } 357 358 359 /** 360 * Check that a Comparator exists in the ComparatorRegistry, and if so, 361 * return it. 362 * 363 * @param entry the Entry we want to know it exists 364 * @return The found comparator 365 * @throws LdapException If teh comparator is not found 366 */ 367 protected LdapComparator<?> checkComparatorOidExists( Entry entry ) throws LdapException 368 { 369 String oid = getOid( entry ); 370 371 if ( schemaManager.getComparatorRegistry().contains( oid ) ) 372 { 373 return schemaManager.getComparatorRegistry().get( oid ); 374 } 375 else 376 { 377 throw new LdapSchemaViolationException( ResultCodeEnum.OTHER, 378 I18n.err( I18n.ERR_336, oid ) ); 379 } 380 } 381 382 383 private void checkNewParent( Dn newParent ) throws LdapException 384 { 385 if ( newParent.size() != 3 ) 386 { 387 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, 388 I18n.err( I18n.ERR_357 ) ); 389 } 390 391 Rdn rdn = newParent.getRdn(); 392 393 if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals( 394 SchemaConstants.OU_AT_OID ) ) 395 { 396 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_358 ) ); 397 } 398 399 if ( !rdn.getValue().equalsIgnoreCase( SchemaConstants.COMPARATORS_AT ) ) 400 { 401 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_359 ) ); 402 } 403 } 404}