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.server.core.schema.registries.synchronizers; 021 022 023 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext; 024 import org.apache.directory.server.i18n.I18n; 025 import org.apache.directory.shared.ldap.constants.MetaSchemaConstants; 026 import org.apache.directory.shared.ldap.constants.SchemaConstants; 027 import org.apache.directory.shared.ldap.entry.ServerEntry; 028 import org.apache.directory.shared.ldap.exception.LdapException; 029 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException; 030 import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException; 031 import org.apache.directory.shared.ldap.message.ResultCodeEnum; 032 import org.apache.directory.shared.ldap.name.DN; 033 import org.apache.directory.shared.ldap.name.RDN; 034 import org.apache.directory.shared.ldap.schema.ObjectClass; 035 import org.apache.directory.shared.ldap.schema.SchemaManager; 036 import org.apache.directory.shared.ldap.schema.registries.Schema; 037 import org.apache.directory.shared.ldap.util.StringTools; 038 import org.slf4j.Logger; 039 import org.slf4j.LoggerFactory; 040 041 042 /** 043 * 044 * 045 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 046 * @version $Rev$, $Date$ 047 */ 048 public class ObjectClassSynchronizer extends AbstractRegistrySynchronizer 049 { 050 /** A logger for this class */ 051 private static final Logger LOG = LoggerFactory.getLogger( ObjectClassSynchronizer.class ); 052 053 054 /** 055 * Creates a new instance of ObjectClassSynchronizer. 056 * 057 * @param schemaManager The global schemaManager 058 * @throws Exception If the initialization failed 059 */ 060 public ObjectClassSynchronizer( SchemaManager schemaManager ) throws Exception 061 { 062 super( schemaManager ); 063 } 064 065 066 /** 067 * {@inheritDoc} 068 */ 069 public boolean modify( ModifyOperationContext opContext, ServerEntry targetEntry, boolean cascade ) 070 throws Exception 071 { 072 DN name = opContext.getDn(); 073 ServerEntry entry = opContext.getEntry(); 074 String oid = getOid( entry ); 075 ObjectClass oc = factory.getObjectClass( schemaManager, targetEntry, schemaManager.getRegistries(), 076 getSchemaName( name ) ); 077 String schemaName = getSchemaName( entry.getDn() ); 078 079 if ( isSchemaEnabled( schemaName ) ) 080 { 081 schemaManager.unregisterObjectClass( oid ); 082 schemaManager.add( oc ); 083 084 return SCHEMA_MODIFIED; 085 } 086 087 return SCHEMA_UNCHANGED; 088 } 089 090 091 /** 092 * {@inheritDoc} 093 */ 094 public void add( ServerEntry entry ) throws Exception 095 { 096 DN dn = entry.getDn(); 097 DN parentDn = ( DN ) dn.clone(); 098 parentDn.remove( parentDn.size() - 1 ); 099 100 // The parent DN must be ou=objectclasses,cn=<schemaName>,ou=schema 101 checkParent( parentDn, schemaManager, SchemaConstants.OBJECT_CLASS ); 102 103 // The new schemaObject's OID must not already exist 104 checkOidIsUnique( entry ); 105 106 // Build the new ObjectClass from the given entry 107 String schemaName = getSchemaName( dn ); 108 109 ObjectClass objectClass = factory.getObjectClass( schemaManager, entry, schemaManager.getRegistries(), 110 schemaName ); 111 112 // At this point, the constructed ObjectClass has not been checked against the 113 // existing Registries. It may be broken (missing SUP, or such), it will be checked 114 // there, if the schema and the ObjectClass are both enabled. 115 Schema schema = schemaManager.getLoadedSchema( schemaName ); 116 117 if ( schema.isEnabled() && objectClass.isEnabled() ) 118 { 119 if ( schemaManager.add( objectClass ) ) 120 { 121 LOG.debug( "Added {} into the enabled schema {}", dn.getName(), schemaName ); 122 } 123 else 124 { 125 // We have some error : reject the addition and get out 126 String msg = I18n.err( I18n.ERR_373, entry.getDn().getName(), 127 StringTools.listToString( schemaManager.getErrors() ) ); 128 LOG.info( msg ); 129 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 130 } 131 132 } 133 else 134 { 135 LOG.debug( "The ObjectClass {} cannot be added in the disabled schema {}.", objectClass, schemaName ); 136 } 137 } 138 139 140 /** 141 * {@inheritDoc} 142 */ 143 public void delete( ServerEntry entry, boolean cascade ) throws Exception 144 { 145 DN dn = entry.getDn(); 146 DN parentDn = ( DN ) dn.clone(); 147 parentDn.remove( parentDn.size() - 1 ); 148 149 // The parent DN must be ou=objectclasses,cn=<schemaName>,ou=schema 150 checkParent( parentDn, schemaManager, SchemaConstants.OBJECT_CLASS ); 151 152 // Get the ObjectClass from the given entry ( it has been grabbed from the server earlier) 153 String schemaName = getSchemaName( entry.getDn() ); 154 155 // Get the schema 156 Schema schema = schemaManager.getLoadedSchema( schemaName ); 157 158 if ( schema.isDisabled() ) 159 { 160 // The schema is disabled, nothing to do. 161 LOG.debug( "The ObjectClass {} cannot be removed from the disabled schema {}.", 162 dn.getName(), schemaName ); 163 164 return; 165 } 166 167 // Test that the Oid exists 168 ObjectClass objectClass = ( ObjectClass ) checkOidExists( entry ); 169 170 if ( schema.isEnabled() && objectClass.isEnabled() ) 171 { 172 if ( schemaManager.delete( objectClass ) ) 173 { 174 LOG.debug( "Removed {} from the schema {}", objectClass, schemaName ); 175 } 176 else 177 { 178 // We have some error : reject the deletion and get out 179 String msg = I18n.err( I18n.ERR_374, entry.getDn().getName(), 180 StringTools.listToString( schemaManager.getErrors() ) ); 181 LOG.info( msg ); 182 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 183 } 184 } 185 else 186 { 187 LOG.debug( "Removed {} from the disabled schema {}", objectClass, schemaName ); 188 } 189 } 190 191 192 /** 193 * {@inheritDoc} 194 */ 195 public void rename( ServerEntry entry, RDN newRdn, boolean cascade ) throws Exception 196 { 197 String schemaName = getSchemaName( entry.getDn() ); 198 ObjectClass oldOc = factory.getObjectClass( schemaManager, entry, schemaManager.getRegistries(), schemaName ); 199 200 // Dependency constraints are not managed by this class 201 // Set<ServerEntry> dependees = dao.listObjectClassDependents( oldOc ); 202 // 203 // if ( dependees != null && dependees.size() > 0 ) 204 // { 205 // throw new LdapUnwillingToPerformException( "The objectClass with OID " + oldOc.getOid() 206 // + " cannot be deleted until all entities" 207 // + " using this objectClass have also been deleted. The following dependees exist: " 208 // + getOids( dependees ), 209 // ResultCodeEnum.UNWILLING_TO_PERFORM ); 210 // } 211 212 ServerEntry targetEntry = ( ServerEntry ) entry.clone(); 213 String newOid = ( String ) newRdn.getNormValue(); 214 targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid ); 215 216 // Inject the new DN 217 DN newDn = new DN( targetEntry.getDn() ); 218 newDn.remove( newDn.size() - 1 ); 219 newDn.add( newRdn ); 220 221 checkOidIsUnique( newOid ); 222 ObjectClass oc = factory.getObjectClass( schemaManager, targetEntry, schemaManager.getRegistries(), schemaName ); 223 224 if ( isSchemaEnabled( schemaName ) ) 225 { 226 // Check that the entry has no descendant 227 if ( schemaManager.getObjectClassRegistry().hasDescendants( oldOc.getOid() ) ) 228 { 229 String msg = I18n.err( I18n.ERR_375, entry.getDn().getName(), newDn ); 230 231 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 232 } 233 234 schemaManager.unregisterObjectClass( oldOc.getOid() ); 235 schemaManager.add( oc ); 236 } 237 else 238 { 239 unregisterOids( oldOc ); 240 registerOids( oc ); 241 } 242 } 243 244 245 public void moveAndRename( DN oriChildName, DN newParentName, RDN newRdn, boolean deleteOldRn, 246 ServerEntry entry, boolean cascade ) throws Exception 247 { 248 checkNewParent( newParentName ); 249 String oldSchemaName = getSchemaName( oriChildName ); 250 ObjectClass oldOc = factory.getObjectClass( schemaManager, entry, schemaManager.getRegistries(), oldSchemaName ); 251 252 // this class does not handle dependencies 253 // Set<ServerEntry> dependees = dao.listObjectClassDependents( oldOc ); 254 // if ( dependees != null && dependees.size() > 0 ) 255 // { 256 // throw new LdapUnwillingToPerformException( "The objectClass with OID " + oldOc.getOid() 257 // + " cannot be deleted until all entities" 258 // + " using this objectClass have also been deleted. The following dependees exist: " 259 // + getOids( dependees ), 260 // ResultCodeEnum.UNWILLING_TO_PERFORM ); 261 // } 262 263 String newSchemaName = getSchemaName( newParentName ); 264 ServerEntry targetEntry = ( ServerEntry ) entry.clone(); 265 String newOid = ( String ) newRdn.getNormValue(); 266 checkOidIsUnique( newOid ); 267 targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid ); 268 ObjectClass oc = factory.getObjectClass( schemaManager, targetEntry, schemaManager.getRegistries(), 269 newSchemaName ); 270 271 if ( isSchemaEnabled( oldSchemaName ) ) 272 { 273 schemaManager.unregisterObjectClass( oldOc.getOid() ); 274 } 275 else 276 { 277 unregisterOids( oldOc ); 278 } 279 280 if ( isSchemaEnabled( newSchemaName ) ) 281 { 282 schemaManager.add( oc ); 283 } 284 else 285 { 286 registerOids( oc ); 287 } 288 } 289 290 291 public void move( DN oriChildName, DN newParentName, ServerEntry entry, boolean cascade ) throws Exception 292 { 293 checkNewParent( newParentName ); 294 String oldSchemaName = getSchemaName( oriChildName ); 295 String newSchemaName = getSchemaName( newParentName ); 296 ObjectClass oldAt = factory.getObjectClass( schemaManager, entry, schemaManager.getRegistries(), oldSchemaName ); 297 298 // dependencies are not managed by this class 299 // Set<ServerEntry> dependees = dao.listObjectClassDependents( oldAt ); 300 // if ( dependees != null && dependees.size() > 0 ) 301 // {s 302 // throw new LdapUnwillingToPerformException( "The objectClass with OID " + oldAt.getOid() 303 // + " cannot be deleted until all entities" 304 // + " using this objectClass have also been deleted. The following dependees exist: " 305 // + getOids( dependees ), 306 // ResultCodeEnum.UNWILLING_TO_PERFORM ); 307 // } 308 309 ObjectClass oc = factory.getObjectClass( schemaManager, entry, schemaManager.getRegistries(), newSchemaName ); 310 311 if ( isSchemaEnabled( oldSchemaName ) ) 312 { 313 schemaManager.unregisterObjectClass( oldAt.getOid() ); 314 } 315 else 316 { 317 unregisterOids( oldAt ); 318 } 319 320 if ( isSchemaEnabled( newSchemaName ) ) 321 { 322 schemaManager.add( oc ); 323 } 324 else 325 { 326 registerOids( oc ); 327 } 328 } 329 330 331 private void checkNewParent( DN newParent ) throws LdapException 332 { 333 if ( newParent.size() != 3 ) 334 { 335 throw new LdapInvalidDnException( 336 ResultCodeEnum.NAMING_VIOLATION, 337 "The parent dn of a objectClass should be at most 3 name components in length." ); 338 } 339 340 RDN rdn = newParent.getRdn(); 341 342 if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals( 343 SchemaConstants.OU_AT_OID ) ) 344 { 345 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, 346 I18n.err( I18n.ERR_376 ) ); 347 } 348 349 if ( !( ( String ) rdn.getNormValue() ).equalsIgnoreCase( SchemaConstants.OBJECT_CLASSES_AT ) ) 350 { 351 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, 352 I18n.err( I18n.ERR_377 ) ); 353 } 354 } 355 }