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.MatchingRule;
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     * 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     * @version $Rev$, $Date$
048     */
049    public class MatchingRuleSynchronizer extends AbstractRegistrySynchronizer
050    {
051        /** A logger for this class */
052        private static final Logger LOG = LoggerFactory.getLogger( MatchingRuleSynchronizer.class );
053    
054    
055        /**
056         * Creates a new instance of MatchingRuleSynchronizer.
057         *
058         * @param schemaManager The global schemaManager
059         * @throws Exception If the initialization failed
060         */
061        public MatchingRuleSynchronizer( SchemaManager schemaManager ) throws Exception
062        {
063            super( schemaManager );
064        }
065    
066    
067        /**
068         * {@inheritDoc}
069         */
070        public boolean modify( ModifyOperationContext opContext, ServerEntry targetEntry, boolean cascade )
071            throws Exception
072        {
073            DN name = opContext.getDn();
074            ServerEntry entry = opContext.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        public void add( ServerEntry entry ) throws Exception
099        {
100            DN dn = entry.getDn();
101            DN parentDn = ( DN ) dn.clone();
102            parentDn.remove( parentDn.size() - 1 );
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                        StringTools.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        public void delete( ServerEntry entry, boolean cascade ) throws Exception
147        {
148            DN dn = entry.getDn();
149            DN parentDn = ( DN ) dn.clone();
150            parentDn.remove( parentDn.size() - 1 );
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                        StringTools.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        public void rename( ServerEntry entry, RDN newRdn, boolean cascade ) throws Exception
200        {
201            String schemaName = getSchemaName( entry.getDn() );
202            MatchingRule oldMr = factory.getMatchingRule( schemaManager, entry, schemaManager.getRegistries(), schemaName );
203            ServerEntry targetEntry = ( ServerEntry ) entry.clone();
204            String newOid = ( String ) newRdn.getNormValue();
205            checkOidIsUnique( newOid );
206    
207            targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid );
208            MatchingRule mr = factory.getMatchingRule( schemaManager, targetEntry, schemaManager.getRegistries(),
209                schemaName );
210    
211            if ( isSchemaEnabled( schemaName ) )
212            {
213                schemaManager.unregisterMatchingRule( oldMr.getOid() );
214                schemaManager.add( mr );
215            }
216            else
217            {
218                unregisterOids( oldMr );
219                registerOids( mr );
220            }
221        }
222    
223    
224        public void moveAndRename( DN oriChildName, DN newParentName, RDN newRdn, boolean deleteOldRn,
225            ServerEntry entry, boolean cascade ) throws Exception
226        {
227            checkNewParent( newParentName );
228            String oldSchemaName = getSchemaName( oriChildName );
229            String newSchemaName = getSchemaName( newParentName );
230            MatchingRule oldMr = factory.getMatchingRule( schemaManager, entry, schemaManager.getRegistries(),
231                oldSchemaName );
232            ServerEntry targetEntry = ( ServerEntry ) entry.clone();
233            String newOid = ( String ) newRdn.getNormValue();
234            checkOidIsUnique( newOid );
235    
236            targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid );
237            MatchingRule mr = factory.getMatchingRule( schemaManager, targetEntry, schemaManager.getRegistries(),
238                newSchemaName );
239    
240            if ( isSchemaEnabled( oldSchemaName ) )
241            {
242                schemaManager.unregisterMatchingRule( oldMr.getOid() );
243            }
244            else
245            {
246                unregisterOids( oldMr );
247            }
248    
249            if ( isSchemaEnabled( newSchemaName ) )
250            {
251                schemaManager.add( mr );
252            }
253            else
254            {
255                registerOids( mr );
256            }
257        }
258    
259    
260        public void move( DN oriChildName, DN newParentName, ServerEntry entry, boolean cascade ) throws Exception
261        {
262            checkNewParent( newParentName );
263            String oldSchemaName = getSchemaName( oriChildName );
264            String newSchemaName = getSchemaName( newParentName );
265            MatchingRule oldMr = factory.getMatchingRule( schemaManager, entry, schemaManager.getRegistries(),
266                oldSchemaName );
267            MatchingRule newMr = factory.getMatchingRule( schemaManager, entry, schemaManager.getRegistries(),
268                newSchemaName );
269    
270            if ( isSchemaEnabled( oldSchemaName ) )
271            {
272                schemaManager.unregisterMatchingRule( oldMr.getOid() );
273            }
274            else
275            {
276                unregisterOids( oldMr );
277            }
278    
279            if ( isSchemaEnabled( newSchemaName ) )
280            {
281                schemaManager.add( newMr );
282            }
283            else
284            {
285                registerOids( newMr );
286            }
287        }
288    
289    
290        private void checkNewParent( DN newParent ) throws LdapException
291        {
292            if ( newParent.size() != 3 )
293            {
294                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
295                    I18n.err( I18n.ERR_361 ) );
296            }
297    
298            RDN rdn = newParent.getRdn();
299            
300            if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals(
301                SchemaConstants.OU_AT_OID ) )
302            {
303                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
304                    I18n.err( I18n.ERR_362 ) );
305            }
306    
307            if ( !( ( String ) rdn.getNormValue() ).equalsIgnoreCase( SchemaConstants.MATCHING_RULES_AT ) )
308            {
309                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
310                    I18n.err( I18n.ERR_363 ) );
311            }
312        }
313    }