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 java.util.ArrayList;
024    import java.util.List;
025    
026    import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
027    import org.apache.directory.server.i18n.I18n;
028    import org.apache.directory.shared.ldap.constants.MetaSchemaConstants;
029    import org.apache.directory.shared.ldap.constants.SchemaConstants;
030    import org.apache.directory.shared.ldap.entry.ServerEntry;
031    import org.apache.directory.shared.ldap.exception.LdapException;
032    import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
033    import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
034    import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException;
035    import org.apache.directory.shared.ldap.message.ResultCodeEnum;
036    import org.apache.directory.shared.ldap.name.DN;
037    import org.apache.directory.shared.ldap.name.RDN;
038    import org.apache.directory.shared.ldap.schema.LdapComparator;
039    import org.apache.directory.shared.ldap.schema.SchemaManager;
040    import org.apache.directory.shared.ldap.schema.registries.Schema;
041    import org.apache.directory.shared.ldap.util.StringTools;
042    import org.slf4j.Logger;
043    import org.slf4j.LoggerFactory;
044    
045    
046    /**
047     * A handler for operations performed to add, delete, modify, rename and 
048     * move schema comparators.
049     *
050     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
051     * @version $Rev$, $Date$
052     */
053    public class ComparatorSynchronizer extends AbstractRegistrySynchronizer
054    {
055        /** A logger for this class */
056        private static final Logger LOG = LoggerFactory.getLogger( ComparatorSynchronizer.class );
057    
058    
059        /**
060         * Creates a new instance of ComparatorSynchronizer.
061         *
062         * @param schemaManager The global schemaManager
063         * @throws Exception If the initialization failed
064         */
065        public ComparatorSynchronizer( SchemaManager schemaManager ) throws Exception
066        {
067            super( schemaManager );
068        }
069    
070    
071        /**
072         * {@inheritDoc}
073         */
074        public boolean modify( ModifyOperationContext opContext, ServerEntry targetEntry, boolean cascade )
075            throws Exception
076        {
077            DN name = opContext.getDn();
078            ServerEntry entry = opContext.getEntry();
079            String schemaName = getSchemaName( name );
080            String oid = getOid( entry );
081            LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, targetEntry, schemaManager
082                .getRegistries(), schemaName );
083    
084            if ( isSchemaEnabled( schemaName ) )
085            {
086                comparator.setSchemaName( schemaName );
087    
088                schemaManager.unregisterComparator( oid );
089                schemaManager.add( comparator );
090    
091                return SCHEMA_MODIFIED;
092            }
093    
094            return SCHEMA_UNCHANGED;
095        }
096    
097    
098        /**
099         * {@inheritDoc}
100         */
101        public void add( ServerEntry entry ) throws Exception
102        {
103            DN dn = entry.getDn();
104            DN parentDn = ( DN ) dn.clone();
105            parentDn.remove( parentDn.size() - 1 );
106    
107            // The parent DN must be ou=comparators,cn=<schemaName>,ou=schema
108            checkParent( parentDn, schemaManager, SchemaConstants.COMPARATOR );
109    
110            // The new schemaObject's OID must not already exist
111            checkOidIsUniqueForComparator( entry );
112    
113            // Build the new Comparator from the given entry
114            String schemaName = getSchemaName( dn );
115    
116            LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(),
117                schemaName );
118    
119            // At this point, the constructed LdapComparator has not been checked against the 
120            // existing Registries. It will be checked there, if the schema and the 
121            // LdapComparator are both enabled.
122            Schema schema = schemaManager.getLoadedSchema( schemaName );
123    
124            if ( schema.isEnabled() && comparator.isEnabled() )
125            {
126                if ( schemaManager.add( comparator ) )
127                {
128                    LOG.debug( "Added {} into the enabled schema {}", dn.getName(), schemaName );
129                }
130                else
131                {
132                    // We have some error : reject the addition and get out
133                    String msg = I18n.err( I18n.ERR_350, entry.getDn().getName(), StringTools.listToString( 
134                        schemaManager.getErrors() ) );
135                    LOG.info( msg );
136                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
137                }
138            }
139            else
140            {
141                LOG.debug( "The Comparator {} cannot be added in the disabled schema {}", dn.getName(), schemaName );
142            }
143        }
144    
145    
146        /**
147         * {@inheritDoc}
148         */
149        public void delete( ServerEntry entry, boolean cascade ) throws Exception
150        {
151            DN dn = entry.getDn();
152            DN parentDn = ( DN ) dn.clone();
153            parentDn.remove( parentDn.size() - 1 );
154    
155            // The parent DN must be ou=comparators,cn=<schemaName>,ou=schema
156            checkParent( parentDn, schemaManager, SchemaConstants.COMPARATOR );
157    
158            // Get the SchemaName
159            String schemaName = getSchemaName( entry.getDn() );
160    
161            // Get the Schema
162            Schema schema = schemaManager.getLoadedSchema( schemaName );
163    
164            if ( schema.isDisabled() )
165            {
166                // The schema is disabled, nothing to do.
167                LOG.debug( "The Comparator {} cannot be deleted from the disabled schema {}", dn.getName(), schemaName );
168                
169                return;
170            }
171    
172            // Test that the Oid exists
173            LdapComparator<?> comparator = null;
174    
175            try
176            {
177                comparator = ( LdapComparator<?> ) checkComparatorOidExists( entry );
178            }
179            catch ( LdapSchemaViolationException lsve )
180            {
181                // The comparator does not exist
182                comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(), schemaName );
183    
184                if ( schemaManager.getRegistries().contains( comparator ) )
185                {
186                    // Remove the Comparator from the schema/SchemaObject Map
187                    schemaManager.getRegistries().dissociateFromSchema( comparator );
188    
189                    // Ok, we can exit. 
190                    return;
191                }
192                else
193                {
194                    // Ok, definitively an error
195                    String msg = I18n.err( I18n.ERR_351, entry.getDn().getName() );
196                    LOG.info( msg );
197                    throw new LdapSchemaViolationException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
198                }
199            }
200    
201            List<Throwable> errors = new ArrayList<Throwable>();
202    
203            if ( schema.isEnabled() && comparator.isEnabled() )
204            {
205                if ( schemaManager.delete( comparator ) )
206                {
207                    LOG.debug( "Deleted {} from the enabled schema {}", dn.getName(), schemaName );
208                }
209                else
210                {
211                    String msg = I18n.err( I18n.ERR_352, entry.getDn().getName(), StringTools.listToString( 
212                        errors ) );
213                    LOG.info( msg );
214                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
215                }
216            }
217            else
218            {
219                LOG.debug( "The Comparator {} cannot be deleted from the disabled schema {}", dn.getName(), schemaName );
220            }
221        }
222    
223    
224        /**
225         * {@inheritDoc}
226         */
227        public void rename( ServerEntry entry, RDN newRdn, boolean cascade ) throws Exception
228        {
229            String oldOid = getOid( entry );
230    
231            if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) )
232            {
233                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
234                    I18n.err( I18n.ERR_353, oldOid ) );
235            }
236    
237            String oid = ( String ) newRdn.getNormValue();
238            checkOidIsUniqueForComparator( oid );
239    
240            String schemaName = getSchemaName( entry.getDn() );
241    
242            if ( isSchemaEnabled( schemaName ) )
243            {
244                // Inject the new OID in the entry
245                ServerEntry targetEntry = ( ServerEntry ) entry.clone();
246                String newOid = ( String ) newRdn.getNormValue();
247                checkOidIsUnique( newOid );
248                targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid );
249    
250                // Inject the new DN
251                DN newDn = new DN( targetEntry.getDn() );
252                newDn.remove( newDn.size() - 1 );
253                newDn.add( newRdn );
254                targetEntry.setDn( newDn );
255    
256                // Register the new comparator, and unregister the old one
257                LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, targetEntry, schemaManager
258                    .getRegistries(), schemaName );
259                schemaManager.unregisterComparator( oldOid );
260                schemaManager.add( comparator );
261            }
262        }
263    
264    
265        public void moveAndRename( DN oriChildName, DN newParentName, RDN newRdn, boolean deleteOldRn,
266            ServerEntry entry, boolean cascade ) throws Exception
267        {
268            checkNewParent( newParentName );
269            String oldOid = getOid( entry );
270    
271            if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) )
272            {
273                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
274                    I18n.err( I18n.ERR_353, oldOid ) );
275            }
276    
277            String oid = ( String ) newRdn.getNormValue();
278            checkOidIsUniqueForComparator( oid );
279    
280            String newSchemaName = getSchemaName( newParentName );
281    
282            LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(),
283                newSchemaName );
284    
285            String oldSchemaName = getSchemaName( oriChildName );
286    
287            if ( isSchemaEnabled( oldSchemaName ) )
288            {
289                schemaManager.unregisterComparator( oldOid );
290            }
291    
292            if ( isSchemaEnabled( newSchemaName ) )
293            {
294                schemaManager.add( comparator );
295            }
296        }
297    
298    
299        public void move( DN oriChildName, DN newParentName, ServerEntry entry, boolean cascade ) throws Exception
300        {
301            checkNewParent( newParentName );
302            String oid = getOid( entry );
303    
304            if ( schemaManager.getMatchingRuleRegistry().contains( oid ) )
305            {
306                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
307                    I18n.err( I18n.ERR_354, oid ) );
308            }
309    
310            String newSchemaName = getSchemaName( newParentName );
311    
312            LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(),
313                newSchemaName );
314    
315            String oldSchemaName = getSchemaName( oriChildName );
316    
317            if ( isSchemaEnabled( oldSchemaName ) )
318            {
319                schemaManager.unregisterComparator( oid );
320            }
321    
322            if ( isSchemaEnabled( newSchemaName ) )
323            {
324                schemaManager.add( comparator );
325            }
326        }
327    
328    
329        private void checkOidIsUniqueForComparator( String oid ) throws LdapSchemaViolationException
330        {
331            if ( schemaManager.getComparatorRegistry().contains( oid ) )
332            {
333                throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
334                    I18n.err( I18n.ERR_355, oid ) );
335            }
336        }
337    
338    
339        private void checkOidIsUniqueForComparator( ServerEntry entry ) throws Exception
340        {
341            String oid = getOid( entry );
342    
343            if ( schemaManager.getComparatorRegistry().contains( oid ) )
344            {
345                throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
346                    I18n.err( I18n.ERR_355, oid ) );
347            }
348        }
349    
350    
351        /**
352         * Check that a Comparator exists in the ComparatorRegistry, and if so,
353         * return it.
354         */
355        protected LdapComparator<?> checkComparatorOidExists( ServerEntry entry ) throws Exception
356        {
357            String oid = getOid( entry );
358    
359            if ( schemaManager.getComparatorRegistry().contains( oid ) )
360            {
361                return ( LdapComparator<?> ) schemaManager.getComparatorRegistry().get( oid );
362            }
363            else
364            {
365                throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
366                    I18n.err( I18n.ERR_336, oid ) );
367            }
368        }
369    
370    
371        private void checkNewParent( DN newParent ) throws LdapException
372        {
373            if ( newParent.size() != 3 )
374            {
375                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
376                    I18n.err( I18n.ERR_357 ) );
377            }
378    
379            RDN rdn = newParent.getRdn();
380    
381            if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals(
382                SchemaConstants.OU_AT_OID ) )
383            {
384                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_358 ) );
385            }
386    
387            if ( !( ( String ) rdn.getNormValue() ).equalsIgnoreCase( SchemaConstants.COMPARATORS_AT ) )
388            {
389                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_359 ) );
390            }
391        }
392    }