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.LdapSchemaViolationException;
031    import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException;
032    import org.apache.directory.shared.ldap.message.ResultCodeEnum;
033    import org.apache.directory.shared.ldap.name.DN;
034    import org.apache.directory.shared.ldap.name.RDN;
035    import org.apache.directory.shared.ldap.schema.SchemaManager;
036    import org.apache.directory.shared.ldap.schema.SyntaxChecker;
037    import org.apache.directory.shared.ldap.schema.registries.Registries;
038    import org.apache.directory.shared.ldap.schema.registries.Schema;
039    import org.apache.directory.shared.ldap.util.StringTools;
040    import org.slf4j.Logger;
041    import org.slf4j.LoggerFactory;
042    
043    
044    /**
045     * A synchronizer which detects changes to syntaxCheckers and updates the 
046     * respective {@link Registries}.
047     *
048     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049     * @version $Rev$, $Date$
050     */
051    public class SyntaxCheckerSynchronizer extends AbstractRegistrySynchronizer
052    {
053        /** A logger for this class */
054        private static final Logger LOG = LoggerFactory.getLogger( SyntaxCheckerSynchronizer.class );
055    
056    
057        /**
058         * Creates a new instance of SyntaxCheckerSynchronizer.
059         *
060         * @param schemaManager The global schemaManager
061         * @throws Exception If the initialization failed
062         */
063        public SyntaxCheckerSynchronizer( SchemaManager schemaManager ) throws Exception
064        {
065            super( schemaManager );
066        }
067    
068    
069        /**
070         * {@inheritDoc}
071         */
072        public boolean modify( ModifyOperationContext opContext, ServerEntry targetEntry, boolean cascade )
073            throws Exception
074        {
075            DN name = opContext.getDn();
076            ServerEntry entry = opContext.getEntry();
077            String schemaName = getSchemaName( name );
078            String oid = getOid( entry );
079            SyntaxChecker syntaxChecker = factory.getSyntaxChecker( schemaManager, targetEntry, schemaManager
080                .getRegistries(), schemaName );
081    
082            if ( isSchemaEnabled( schemaName ) )
083            {
084                syntaxChecker.setSchemaName( schemaName );
085    
086                schemaManager.unregisterSyntaxChecker( oid );
087                schemaManager.add( syntaxChecker );
088    
089                return SCHEMA_MODIFIED;
090            }
091    
092            return SCHEMA_UNCHANGED;
093        }
094    
095    
096        /**
097         * {@inheritDoc}
098         */
099        public void add( ServerEntry entry ) throws Exception
100        {
101            DN dn = entry.getDn();
102            DN parentDn = ( DN ) dn.clone();
103            parentDn.remove( parentDn.size() - 1 );
104    
105            // The parent DN must be ou=syntaxcheckers,cn=<schemaName>,ou=schema
106            checkParent( parentDn, schemaManager, SchemaConstants.SYNTAX_CHECKER );
107    
108            // The new schemaObject's OID must not already exist
109            checkOidIsUniqueForSyntaxChecker( entry );
110    
111            // Build the new SyntaxChecker from the given entry
112            String schemaName = getSchemaName( dn );
113    
114            SyntaxChecker syntaxChecker = factory.getSyntaxChecker( schemaManager, entry, schemaManager.getRegistries(),
115                schemaName );
116    
117            // At this point, the constructed SyntaxChecker has not been checked against the 
118            // existing Registries. It will be checked there, if the schema and the 
119            // SyntaxChecker are both enabled.
120            Schema schema = schemaManager.getLoadedSchema( schemaName );
121    
122            if ( schema.isEnabled() && syntaxChecker.isEnabled() )
123            {
124                if ( schemaManager.add( syntaxChecker ) )
125                {
126                    LOG.debug( "Added {} into the enabled schema {}", dn.getName(), schemaName );
127                }
128                else
129                {
130                    String msg = I18n.err( I18n.ERR_386, 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 SyntaxChecker {} cannot be added in the disabled schema {}", dn.getName(), 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=syntaxcheckers,cn=<schemaName>,ou=schema
153            checkParent( parentDn, schemaManager, SchemaConstants.SYNTAX_CHECKER );
154    
155            // Get the SyntaxChecker's instance
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 SyntaxChecker {} cannot be deleted from the disabled schema {}", dn.getName(), schemaName );
165                
166                return;
167            }
168    
169            // Test that the Oid exists
170            SyntaxChecker syntaxChecker = null;
171    
172            try
173            {
174                syntaxChecker = ( SyntaxChecker ) checkSyntaxCheckerOidExists( entry );
175            }
176            catch ( LdapSchemaViolationException lsve )
177            {
178                // The syntaxChecker does not exist
179                syntaxChecker = factory.getSyntaxChecker( schemaManager, entry, schemaManager.getRegistries(), schemaName );
180    
181                if ( schemaManager.getRegistries().contains( syntaxChecker ) )
182                {
183                    // Remove the syntaxChecker from the schema/SchemaObject Map
184                    schemaManager.getRegistries().dissociateFromSchema( syntaxChecker );
185    
186                    // Ok, we can exit. 
187                    return;
188                }
189                else
190                {
191                    // Ok, definitively an error
192                    String msg = I18n.err( I18n.ERR_387, entry.getDn().getName() );
193                    LOG.info( msg );
194                    throw new LdapSchemaViolationException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
195                }
196            }
197    
198            if ( schema.isEnabled() && syntaxChecker.isEnabled() )
199            {
200                if ( schemaManager.delete( syntaxChecker ) )
201                {
202                    LOG.debug( "Deleted {} from the enabled schema {}", dn.getName(), schemaName );
203                }
204                else
205                {
206                    String msg = I18n.err( I18n.ERR_386, entry.getDn().getName(),
207                        StringTools.listToString( schemaManager.getErrors() ) );
208                    LOG.info( msg );
209                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
210                }
211            }
212            else
213            {
214                LOG.debug( "The syntaxChecker {} cannot be deleted from the disabled schema {}", dn.getName(), schemaName );
215            }
216        }
217    
218    
219        /**
220         * {@inheritDoc}
221         */
222        public void rename( ServerEntry entry, RDN newRdn, boolean cascade ) throws Exception
223        {
224            String oldOid = getOid( entry );
225            String schemaName = getSchemaName( entry.getDn() );
226    
227            if ( schemaManager.getLdapSyntaxRegistry().contains( oldOid ) )
228            {
229                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
230                    I18n.err( I18n.ERR_389, oldOid ) );
231            }
232    
233            ServerEntry targetEntry = ( ServerEntry ) entry.clone();
234            String newOid = ( String ) newRdn.getNormValue();
235    
236            if ( schemaManager.getSyntaxCheckerRegistry().contains( newOid ) )
237            {
238                throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
239                    I18n.err( I18n.ERR_390, newOid ) );
240            }
241    
242            targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid );
243    
244            if ( isSchemaEnabled( schemaName ) )
245            {
246                SyntaxChecker syntaxChecker = factory.getSyntaxChecker( schemaManager, targetEntry, schemaManager
247                    .getRegistries(), schemaName );
248                schemaManager.unregisterSyntaxChecker( oldOid );
249                schemaManager.add( syntaxChecker );
250            }
251        }
252    
253    
254        public void moveAndRename( DN oriChildName, DN newParentName, RDN newRdn, boolean deleteOldRn,
255            ServerEntry entry, boolean cascade ) throws Exception
256        {
257            checkNewParent( newParentName );
258            String oldOid = getOid( entry );
259            String oldSchemaName = getSchemaName( oriChildName );
260            String newSchemaName = getSchemaName( newParentName );
261    
262            if ( schemaManager.getLdapSyntaxRegistry().contains( oldOid ) )
263            {
264                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
265                    I18n.err( I18n.ERR_391, oldOid ) );
266            }
267    
268            ServerEntry targetEntry = ( ServerEntry ) entry.clone();
269    
270            String newOid = ( String ) newRdn.getNormValue();
271    
272            if ( schemaManager.getSyntaxCheckerRegistry().contains( newOid ) )
273            {
274                throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
275                    I18n.err( I18n.ERR_390, newOid ) );
276            }
277    
278            targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid );
279            SyntaxChecker syntaxChecker = factory.getSyntaxChecker( schemaManager, targetEntry, schemaManager
280                .getRegistries(), newSchemaName );
281    
282            if ( isSchemaEnabled( oldSchemaName ) )
283            {
284                schemaManager.unregisterSyntaxChecker( oldOid );
285            }
286    
287            if ( isSchemaEnabled( newSchemaName ) )
288            {
289                schemaManager.add( syntaxChecker );
290            }
291        }
292    
293    
294        public void move( DN oriChildName, DN newParentName, ServerEntry entry, boolean cascade ) throws Exception
295        {
296            checkNewParent( newParentName );
297            String oid = getOid( entry );
298            String oldSchemaName = getSchemaName( oriChildName );
299            String newSchemaName = getSchemaName( newParentName );
300    
301            if ( schemaManager.getLdapSyntaxRegistry().contains( oid ) )
302            {
303                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
304                    I18n.err( I18n.ERR_393, oid ) );
305            }
306    
307            SyntaxChecker syntaxChecker = factory.getSyntaxChecker( schemaManager, entry, schemaManager.getRegistries(),
308                newSchemaName );
309    
310            if ( isSchemaEnabled( oldSchemaName ) )
311            {
312                schemaManager.unregisterSyntaxChecker( oid );
313            }
314    
315            if ( isSchemaEnabled( newSchemaName ) )
316            {
317                schemaManager.add( syntaxChecker );
318            }
319        }
320    
321    
322        private void checkOidIsUniqueForSyntaxChecker( ServerEntry entry ) throws Exception
323        {
324            String oid = getOid( entry );
325    
326            if ( schemaManager.getNormalizerRegistry().contains( oid ) )
327            {
328                throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
329                    I18n.err( I18n.ERR_390, oid ) );
330            }
331        }
332    
333        
334        /**
335         * Check that a SyntaxChecker exists in the SyntaxCheckerRegistry, and if so,
336         * return it.
337         */
338        protected SyntaxChecker checkSyntaxCheckerOidExists( ServerEntry entry ) throws Exception
339        {
340            String oid = getOid( entry );
341    
342            if ( schemaManager.getSyntaxCheckerRegistry().contains( oid ) )
343            {
344                return (SyntaxChecker)schemaManager.getSyntaxCheckerRegistry().get( oid );
345            }
346            else
347            {
348                throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
349                    I18n.err( I18n.ERR_336, oid ) );
350            }
351        }
352    
353    
354        private void checkNewParent( DN newParent ) throws LdapException
355        {
356            if ( newParent.size() != 3 )
357            {
358                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
359                    I18n.err( I18n.ERR_396 ) );
360            }
361    
362            RDN rdn = newParent.getRdn();
363            if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals(
364                SchemaConstants.OU_AT_OID ) )
365            {
366                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
367                    I18n.err( I18n.ERR_397 ) );
368            }
369    
370            if ( !( ( String ) rdn.getNormValue() ).equalsIgnoreCase( SchemaConstants.SYNTAX_CHECKERS_AT ) )
371            {
372                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
373                    I18n.err( I18n.ERR_372 ) );
374            }
375        }
376    }