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 }