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