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