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.LdapUnwillingToPerformException;
029import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
030import org.apache.directory.api.ldap.model.name.Dn;
031import org.apache.directory.api.ldap.model.name.Rdn;
032import org.apache.directory.api.ldap.model.schema.MatchingRule;
033import org.apache.directory.api.ldap.model.schema.SchemaManager;
034import org.apache.directory.api.ldap.model.schema.registries.Schema;
035import org.apache.directory.api.util.Strings;
036import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
037import org.apache.directory.server.i18n.I18n;
038import org.slf4j.Logger;
039import org.slf4j.LoggerFactory;
040
041
042/**
043 * A handler for operations performed to add, delete, modify, rename and 
044 * move schema normalizers.
045 *
046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
047 */
048public class MatchingRuleSynchronizer extends AbstractRegistrySynchronizer
049{
050    /** A logger for this class */
051    private static final Logger LOG = LoggerFactory.getLogger( MatchingRuleSynchronizer.class );
052
053
054    /**
055     * Creates a new instance of MatchingRuleSynchronizer.
056     *
057     * @param schemaManager The global schemaManager
058     * @throws Exception If the initialization failed
059     */
060    public MatchingRuleSynchronizer( SchemaManager schemaManager ) throws Exception
061    {
062        super( schemaManager );
063    }
064
065
066    /**
067     * {@inheritDoc}
068     */
069    @Override
070    public boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean cascade )
071        throws LdapException
072    {
073        Dn name = modifyContext.getDn();
074        Entry entry = modifyContext.getEntry();
075        String schemaName = getSchemaName( name );
076        MatchingRule mr = factory.getMatchingRule( schemaManager, targetEntry, schemaManager.getRegistries(),
077            schemaName );
078
079        String oldOid = getOid( entry );
080
081        if ( isSchemaEnabled( schemaName ) )
082        {
083            schemaManager.unregisterMatchingRule( oldOid );
084            schemaManager.add( mr );
085
086            return SCHEMA_MODIFIED;
087        }
088        else
089        {
090            return SCHEMA_UNCHANGED;
091        }
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=matchingrules,cn=<schemaName>,ou=schema
105        checkParent( parentDn, schemaManager, SchemaConstants.MATCHING_RULE );
106
107        // The new schemaObject's OID must not already exist
108        checkOidIsUnique( entry );
109
110        // Build the new MatchingRule from the given entry
111        String schemaName = getSchemaName( dn );
112
113        MatchingRule matchingRule = factory.getMatchingRule( schemaManager, entry, schemaManager.getRegistries(),
114            schemaName );
115
116        // At this point, the constructed MatchingRule has not been checked against the 
117        // existing Registries. It may be broken (missing SUP, or such), it will be checked
118        // there, if the schema and the MatchingRule are both enabled.
119        Schema schema = schemaManager.getLoadedSchema( schemaName );
120
121        if ( schema.isEnabled() && matchingRule.isEnabled() )
122        {
123            if ( schemaManager.add( matchingRule ) )
124            {
125                LOG.debug( "Added {} into the enabled schema {}", dn.getName(), schemaName );
126            }
127            else
128            {
129                // We have some error : reject the addition and get out
130                String msg = I18n.err( I18n.ERR_360, entry.getDn().getName(),
131                    Strings.listToString( schemaManager.getErrors() ) );
132                LOG.info( msg );
133                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
134            }
135        }
136        else
137        {
138            LOG.debug( "The MztchingRule {} cannot be added in the disabled schema {}.", matchingRule, schemaName );
139        }
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=matchingrules,cn=<schemaName>,ou=schema
153        checkParent( parentDn, schemaManager, SchemaConstants.MATCHING_RULE );
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 MatchingRule {} cannot be removed from the disabled schema {}.",
165                dn.getName(), schemaName );
166
167            return;
168        }
169
170        // Test that the Oid exists
171        MatchingRule matchingRule = ( MatchingRule ) checkOidExists( entry );
172
173        if ( schema.isEnabled() && matchingRule.isEnabled() )
174        {
175            if ( schemaManager.delete( matchingRule ) )
176            {
177                LOG.debug( "Removed {} from the schema {}", matchingRule, schemaName );
178            }
179            else
180            {
181                // We have some error : reject the deletion and get out
182                // The schema is disabled. We still have to update the backend
183                String msg = I18n.err( I18n.ERR_360, entry.getDn().getName(),
184                    Strings.listToString( schemaManager.getErrors() ) );
185                LOG.info( msg );
186                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
187            }
188        }
189        else
190        {
191            LOG.debug( "Removed {} from the disabled schema {}", matchingRule, schemaName );
192        }
193    }
194
195
196    /**
197     * {@inheritDoc}
198     */
199    @Override
200    public void rename( Entry entry, Rdn newRdn, boolean cascade ) throws LdapException
201    {
202        String schemaName = getSchemaName( entry.getDn() );
203        MatchingRule oldMr = factory.getMatchingRule( schemaManager, entry, schemaManager.getRegistries(), schemaName );
204        Entry targetEntry = entry.clone();
205        String newOid = newRdn.getValue();
206        checkOidIsUnique( newOid );
207
208        targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid );
209        MatchingRule mr = factory.getMatchingRule( schemaManager, targetEntry, schemaManager.getRegistries(),
210            schemaName );
211
212        if ( isSchemaEnabled( schemaName ) )
213        {
214            schemaManager.unregisterMatchingRule( oldMr.getOid() );
215            schemaManager.add( mr );
216        }
217        else
218        {
219            unregisterOids( oldMr );
220            registerOids( mr );
221        }
222    }
223
224
225    /**
226     * {@inheritDoc}
227     */
228    @Override
229    public void moveAndRename( Dn oriChildName, Dn newParentName, Rdn newRdn, boolean deleteOldRn,
230        Entry entry, boolean cascade ) throws LdapException
231    {
232        checkNewParent( newParentName );
233        String oldSchemaName = getSchemaName( oriChildName );
234        String newSchemaName = getSchemaName( newParentName );
235        MatchingRule oldMr = factory.getMatchingRule( schemaManager, entry, schemaManager.getRegistries(),
236            oldSchemaName );
237        Entry targetEntry = entry.clone();
238        String newOid = newRdn.getValue();
239        checkOidIsUnique( newOid );
240
241        targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid );
242        MatchingRule mr = factory.getMatchingRule( schemaManager, targetEntry, schemaManager.getRegistries(),
243            newSchemaName );
244
245        if ( isSchemaEnabled( oldSchemaName ) )
246        {
247            schemaManager.unregisterMatchingRule( oldMr.getOid() );
248        }
249        else
250        {
251            unregisterOids( oldMr );
252        }
253
254        if ( isSchemaEnabled( newSchemaName ) )
255        {
256            schemaManager.add( mr );
257        }
258        else
259        {
260            registerOids( mr );
261        }
262    }
263
264
265    /**
266     * {@inheritDoc}
267     */
268    @Override
269    public void move( Dn oriChildName, Dn newParentName, Entry entry, boolean cascade ) throws LdapException
270    {
271        checkNewParent( newParentName );
272        String oldSchemaName = getSchemaName( oriChildName );
273        String newSchemaName = getSchemaName( newParentName );
274        MatchingRule oldMr = factory.getMatchingRule( schemaManager, entry, schemaManager.getRegistries(),
275            oldSchemaName );
276        MatchingRule newMr = factory.getMatchingRule( schemaManager, entry, schemaManager.getRegistries(),
277            newSchemaName );
278
279        if ( isSchemaEnabled( oldSchemaName ) )
280        {
281            schemaManager.unregisterMatchingRule( oldMr.getOid() );
282        }
283        else
284        {
285            unregisterOids( oldMr );
286        }
287
288        if ( isSchemaEnabled( newSchemaName ) )
289        {
290            schemaManager.add( newMr );
291        }
292        else
293        {
294            registerOids( newMr );
295        }
296    }
297
298
299    private void checkNewParent( Dn newParent ) throws LdapException
300    {
301        if ( newParent.size() != 3 )
302        {
303            throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
304                I18n.err( I18n.ERR_361 ) );
305        }
306
307        Rdn rdn = newParent.getRdn();
308
309        if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals(
310            SchemaConstants.OU_AT_OID ) )
311        {
312            throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
313                I18n.err( I18n.ERR_362 ) );
314        }
315
316        if ( !rdn.getValue().equalsIgnoreCase( SchemaConstants.MATCHING_RULES_AT ) )
317        {
318            throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
319                I18n.err( I18n.ERR_363 ) );
320        }
321    }
322}