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.Normalizer; 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 * 048 * 049 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 050 */ 051public class NormalizerSynchronizer extends AbstractRegistrySynchronizer 052{ 053 /** A logger for this class */ 054 private static final Logger LOG = LoggerFactory.getLogger( NormalizerSynchronizer.class ); 055 056 057 /** 058 * Creates a new instance of NormalizerSynchronizer. 059 * 060 * @param schemaManager The server schemaManager 061 * @throws Exception If the initialization failed 062 */ 063 public NormalizerSynchronizer( SchemaManager schemaManager ) throws Exception 064 { 065 super( schemaManager ); 066 } 067 068 069 /** 070 * {@inheritDoc} 071 */ 072 @Override 073 public boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean cascade ) 074 throws LdapException 075 { 076 Dn name = modifyContext.getDn(); 077 Entry entry = modifyContext.getEntry(); 078 String schemaName = getSchemaName( name ); 079 String oldOid = getOid( entry ); 080 Normalizer normalizer = factory.getNormalizer( schemaManager, targetEntry, schemaManager.getRegistries(), 081 schemaName ); 082 083 if ( isSchemaEnabled( schemaName ) ) 084 { 085 normalizer.setSchemaName( schemaName ); 086 087 schemaManager.unregisterNormalizer( oldOid ); 088 schemaManager.add( normalizer ); 089 090 return SCHEMA_MODIFIED; 091 } 092 093 return SCHEMA_UNCHANGED; 094 } 095 096 097 /** 098 * {@inheritDoc} 099 */ 100 @Override 101 public void add( Entry entry ) throws LdapException 102 { 103 Dn dn = entry.getDn(); 104 Dn parentDn = dn.getParent(); 105 106 // The parent Dn must be ou=normalizers,cn=<schemaName>,ou=schema 107 checkParent( parentDn, schemaManager, SchemaConstants.NORMALIZER ); 108 109 // The new schemaObject's OID must not already exist 110 checkOidIsUniqueForNormalizer( entry ); 111 112 // Build the new Normalizer from the given entry 113 String schemaName = getSchemaName( dn ); 114 115 Normalizer normalizer = factory.getNormalizer( schemaManager, entry, schemaManager.getRegistries(), schemaName ); 116 117 // At this point, the constructed Normalizer has not been checked against the 118 // existing Registries. It will be checked there, if the schema and the 119 // Normalizer are both enabled. 120 Schema schema = schemaManager.getLoadedSchema( schemaName ); 121 List<Throwable> errors = new ArrayList<>(); 122 123 if ( schema.isEnabled() && normalizer.isEnabled() ) 124 { 125 if ( schemaManager.add( normalizer ) ) 126 { 127 LOG.debug( "Added {} into the enabled schema {}", dn.getName(), schemaName ); 128 } 129 else 130 { 131 String msg = I18n.err( I18n.ERR_364, entry.getDn().getName(), 132 Strings.listToString( errors ) ); 133 LOG.info( msg ); 134 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 135 } 136 } 137 else 138 { 139 // At least, we associates the Normalizer with the schema 140 schemaManager.getRegistries().associateWithSchema( normalizer ); 141 142 if ( !errors.isEmpty() ) 143 { 144 String msg = I18n.err( I18n.ERR_365, entry.getDn().getName(), 145 Strings.listToString( errors ) ); 146 147 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 148 } 149 150 LOG.debug( "The normalizer {} cannot be added in schema {}", dn.getName(), schemaName ); 151 } 152 } 153 154 155 /** 156 * {@inheritDoc} 157 */ 158 @Override 159 public void delete( Entry entry, boolean cascade ) throws LdapException 160 { 161 Dn dn = entry.getDn(); 162 Dn parentDn = dn.getParent(); 163 164 // The parent Dn must be ou=normalizers,cn=<schemaName>,ou=schema 165 checkParent( parentDn, schemaManager, SchemaConstants.NORMALIZER ); 166 167 // Get the Normalizer from the given entry ( it has been grabbed from the server earlier) 168 String schemaName = getSchemaName( entry.getDn() ); 169 Normalizer normalizer = factory.getNormalizer( schemaManager, entry, schemaManager.getRegistries(), schemaName ); 170 171 String oid = normalizer.getOid(); 172 173 if ( isSchemaEnabled( schemaName ) ) 174 { 175 if ( schemaManager.getRegistries().isReferenced( normalizer ) ) 176 { 177 String msg = I18n.err( I18n.ERR_366, entry.getDn().getName(), getReferenced( normalizer ) ); 178 LOG.warn( msg ); 179 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 180 } 181 182 // As the normalizer has the same OID than its attached MR, it won't 183 // be loaded into the schemaManager if it's disabled 184 deleteFromSchema( normalizer, schemaName ); 185 } 186 187 if ( schemaManager.getNormalizerRegistry().contains( oid ) ) 188 { 189 schemaManager.unregisterNormalizer( oid ); 190 LOG.debug( "Removed {} from the enabled schema {}", normalizer, schemaName ); 191 } 192 else 193 { 194 LOG.debug( "Removed {} from the enabled schema {}", normalizer, schemaName ); 195 } 196 } 197 198 199 /** 200 * {@inheritDoc} 201 */ 202 @Override 203 public void rename( Entry entry, Rdn newRdn, boolean cascade ) throws LdapException 204 { 205 String oldOid = getOid( entry ); 206 String schemaName = getSchemaName( entry.getDn() ); 207 208 if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) ) 209 { 210 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, 211 I18n.err( I18n.ERR_367, oldOid ) ); 212 } 213 214 String newOid = newRdn.getValue(); 215 checkOidIsUniqueForNormalizer( newOid ); 216 217 if ( isSchemaEnabled( schemaName ) ) 218 { 219 // Inject the new OID 220 Entry targetEntry = entry.clone(); 221 targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid ); 222 223 // Inject the new Dn 224 Dn newDn = targetEntry.getDn().getParent(); 225 newDn = newDn.add( newRdn ); 226 targetEntry.setDn( newDn ); 227 228 Normalizer normalizer = factory.getNormalizer( schemaManager, targetEntry, schemaManager.getRegistries(), 229 schemaName ); 230 schemaManager.unregisterNormalizer( oldOid ); 231 schemaManager.add( normalizer ); 232 } 233 } 234 235 236 /** 237 * {@inheritDoc} 238 */ 239 @Override 240 public void moveAndRename( Dn oriChildName, Dn newParentName, Rdn newRdn, boolean deleteOldRn, 241 Entry entry, boolean cascade ) throws LdapException 242 { 243 checkNewParent( newParentName ); 244 String oldOid = getOid( entry ); 245 String oldSchemaName = getSchemaName( oriChildName ); 246 String newSchemaName = getSchemaName( newParentName ); 247 248 if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) ) 249 { 250 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, 251 I18n.err( I18n.ERR_367, oldOid ) ); 252 } 253 254 String oid = newRdn.getValue(); 255 checkOidIsUniqueForNormalizer( oid ); 256 Normalizer normalizer = factory.getNormalizer( schemaManager, entry, schemaManager.getRegistries(), 257 newSchemaName ); 258 259 if ( isSchemaEnabled( oldSchemaName ) ) 260 { 261 schemaManager.unregisterNormalizer( oldOid ); 262 } 263 264 if ( isSchemaEnabled( newSchemaName ) ) 265 { 266 schemaManager.add( normalizer ); 267 } 268 } 269 270 271 /** 272 * {@inheritDoc} 273 */ 274 @Override 275 public void move( Dn oriChildName, Dn newParentName, Entry entry, boolean cascade ) throws LdapException 276 { 277 checkNewParent( newParentName ); 278 String oid = getOid( entry ); 279 String oldSchemaName = getSchemaName( oriChildName ); 280 String newSchemaName = getSchemaName( newParentName ); 281 282 if ( schemaManager.getMatchingRuleRegistry().contains( oid ) ) 283 { 284 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, 285 I18n.err( I18n.ERR_368, oid ) ); 286 } 287 288 Normalizer normalizer = factory.getNormalizer( schemaManager, entry, schemaManager.getRegistries(), 289 newSchemaName ); 290 291 if ( isSchemaEnabled( oldSchemaName ) ) 292 { 293 schemaManager.unregisterNormalizer( oid ); 294 } 295 296 if ( isSchemaEnabled( newSchemaName ) ) 297 { 298 schemaManager.add( normalizer ); 299 } 300 } 301 302 303 private void checkOidIsUniqueForNormalizer( String oid ) throws LdapException 304 { 305 if ( schemaManager.getNormalizerRegistry().contains( oid ) ) 306 { 307 throw new LdapSchemaViolationException( ResultCodeEnum.OTHER, 308 I18n.err( I18n.ERR_369, oid ) ); 309 } 310 } 311 312 313 private void checkOidIsUniqueForNormalizer( Entry entry ) throws LdapException 314 { 315 String oid = getOid( entry ); 316 317 if ( schemaManager.getNormalizerRegistry().contains( oid ) ) 318 { 319 throw new LdapSchemaViolationException( ResultCodeEnum.OTHER, 320 I18n.err( I18n.ERR_369, oid ) ); 321 } 322 } 323 324 325 private void checkNewParent( Dn newParent ) throws LdapException 326 { 327 if ( newParent.size() != 3 ) 328 { 329 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_370 ) ); 330 } 331 332 Rdn rdn = newParent.getRdn(); 333 334 if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals( 335 SchemaConstants.OU_AT_OID ) ) 336 { 337 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_371 ) ); 338 } 339 340 if ( !rdn.getValue().equalsIgnoreCase( SchemaConstants.NORMALIZERS_AT ) ) 341 { 342 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_372 ) ); 343 } 344 } 345}