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.Normalizer;
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     *
048     *
049     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
050     * @version $Rev$, $Date$
051     */
052    public class NormalizerSynchronizer extends AbstractRegistrySynchronizer
053    {
054        /** A logger for this class */
055        private static final Logger LOG = LoggerFactory.getLogger( NormalizerSynchronizer.class );
056    
057    
058        /**
059         * Creates a new instance of NormalizerSynchronizer.
060         *
061         * @param registries The global registries
062         * @throws Exception If the initialization failed
063         */
064        public NormalizerSynchronizer( SchemaManager schemaManager ) throws Exception
065        {
066            super( schemaManager );
067        }
068    
069    
070        /**
071         * {@inheritDoc}
072         */
073        public boolean modify( ModifyOperationContext opContext, ServerEntry targetEntry, boolean cascade )
074            throws Exception
075        {
076            DN name = opContext.getDn();
077            ServerEntry entry = opContext.getEntry();
078            String schemaName = getSchemaName( name );
079            String oldOid = getOid( entry );
080            Normalizer normalizer = factory.getNormalizer( schemaManager, targetEntry, schemaManager.getRegistries(),
081                schemaName );
082    
083            if ( isSchemaEnabled( schemaName ) )
084            {
085                normalizer.setSchemaName( schemaName );
086    
087                schemaManager.unregisterNormalizer( oldOid );
088                schemaManager.add( normalizer );
089    
090                return SCHEMA_MODIFIED;
091            }
092    
093            return SCHEMA_UNCHANGED;
094        }
095    
096    
097        /**
098         * {@inheritDoc}
099         */
100        public void add( ServerEntry entry ) throws Exception
101        {
102            DN dn = entry.getDn();
103            DN parentDn = ( DN ) dn.clone();
104            parentDn.remove( parentDn.size() - 1 );
105    
106            // The parent DN must be ou=normalizers,cn=<schemaName>,ou=schema
107            checkParent( parentDn, schemaManager, SchemaConstants.NORMALIZER );
108    
109            // The new schemaObject's OID must not already exist
110            checkOidIsUniqueForNormalizer( entry );
111    
112            // Build the new Normalizer from the given entry
113            String schemaName = getSchemaName( dn );
114    
115            Normalizer normalizer = factory.getNormalizer( schemaManager, entry, schemaManager.getRegistries(), schemaName );
116    
117            // At this point, the constructed Normalizer has not been checked against the 
118            // existing Registries. It will be checked there, if the schema and the 
119            // Normalizer are both enabled.
120            Schema schema = schemaManager.getLoadedSchema( schemaName );
121            List<Throwable> errors = new ArrayList<Throwable>();
122    
123            if ( schema.isEnabled() && normalizer.isEnabled() )
124            {
125                if ( schemaManager.add( normalizer ) )
126                {
127                    LOG.debug( "Added {} into the enabled schema {}", dn.getName(), schemaName );
128                }
129                else
130                {
131                    String msg = I18n.err( I18n.ERR_364, entry.getDn().getName(), 
132                        StringTools.listToString( errors ) );
133                    LOG.info( msg );
134                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
135                }
136            }
137            else
138            {
139                // At least, we associates the Normalizer with the schema
140                schemaManager.getRegistries().associateWithSchema( errors, normalizer );
141    
142                if ( !errors.isEmpty() )
143                {
144                    String msg = I18n.err( I18n.ERR_365, entry.getDn().getName(),
145                        StringTools.listToString( errors ) );
146    
147                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
148                }
149    
150                LOG.debug( "The normalizer {} cannot be added in schema {}", dn.getName(), schemaName );
151            }
152        }
153    
154    
155        /**
156         * {@inheritDoc}
157         */
158        public void delete( ServerEntry entry, boolean cascade ) throws Exception
159        {
160            DN dn = entry.getDn();
161            DN parentDn = ( DN ) dn.clone();
162            parentDn.remove( parentDn.size() - 1 );
163    
164            // The parent DN must be ou=normalizers,cn=<schemaName>,ou=schema
165            checkParent( parentDn, schemaManager, SchemaConstants.NORMALIZER );
166    
167            // Get the Normalizer from the given entry ( it has been grabbed from the server earlier)
168            String schemaName = getSchemaName( entry.getDn() );
169            Normalizer normalizer = factory.getNormalizer( schemaManager, entry, schemaManager.getRegistries(), schemaName );
170    
171            String oid = normalizer.getOid();
172    
173            if ( isSchemaEnabled( schemaName ) )
174            {
175                if ( schemaManager.getRegistries().isReferenced( normalizer ) )
176                {
177                    String msg = I18n.err( I18n.ERR_366, entry.getDn().getName(), getReferenced( normalizer ) );
178                    LOG.warn( msg );
179                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
180                }
181    
182                // As the normalizer has the same OID than its attached MR, it won't
183                // be loaded into the schemaManager if it's disabled
184                deleteFromSchema( normalizer, schemaName );
185            }
186    
187            if ( schemaManager.getNormalizerRegistry().contains( oid ) )
188            {
189                schemaManager.unregisterNormalizer( oid );
190                LOG.debug( "Removed {} from the enabled schema {}", normalizer, schemaName );
191            }
192            else
193            {
194                LOG.debug( "Removed {} from the enabled schema {}", normalizer, schemaName );
195            }
196        }
197    
198    
199        /**
200         * {@inheritDoc}
201         */
202        public void rename( ServerEntry entry, RDN newRdn, boolean cascade ) throws Exception
203        {
204            String oldOid = getOid( entry );
205            String schemaName = getSchemaName( entry.getDn() );
206    
207            if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) )
208            {
209                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
210                    I18n.err( I18n.ERR_367, oldOid ) );
211            }
212    
213            String newOid = ( String ) newRdn.getNormValue();
214            checkOidIsUniqueForNormalizer( newOid );
215    
216            if ( isSchemaEnabled( schemaName ) )
217            {
218                // Inject the new OID
219                ServerEntry targetEntry = ( ServerEntry ) entry.clone();
220                targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid );
221    
222                // Inject the new DN
223                DN newDn = new DN( targetEntry.getDn() );
224                newDn.remove( newDn.size() - 1 );
225                newDn.add( newRdn );
226                targetEntry.setDn( newDn );
227    
228                Normalizer normalizer = factory.getNormalizer( schemaManager, targetEntry, schemaManager.getRegistries(),
229                    schemaName );
230                schemaManager.unregisterNormalizer( oldOid );
231                schemaManager.add( normalizer );
232            }
233        }
234    
235    
236        public void moveAndRename( DN oriChildName, DN newParentName, RDN newRdn, boolean deleteOldRn,
237            ServerEntry entry, boolean cascade ) throws Exception
238        {
239            checkNewParent( newParentName );
240            String oldOid = getOid( entry );
241            String oldSchemaName = getSchemaName( oriChildName );
242            String newSchemaName = getSchemaName( newParentName );
243    
244            if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) )
245            {
246                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
247                    I18n.err( I18n.ERR_367, oldOid ) );
248            }
249    
250            String oid = ( String ) newRdn.getNormValue();
251            checkOidIsUniqueForNormalizer( oid );
252            Normalizer normalizer = factory.getNormalizer( schemaManager, entry, schemaManager.getRegistries(),
253                newSchemaName );
254    
255            if ( isSchemaEnabled( oldSchemaName ) )
256            {
257                schemaManager.unregisterNormalizer( oldOid );
258            }
259    
260            if ( isSchemaEnabled( newSchemaName ) )
261            {
262                schemaManager.add( normalizer );
263            }
264        }
265    
266    
267        public void move( DN oriChildName, DN newParentName, ServerEntry entry, boolean cascade ) throws Exception
268        {
269            checkNewParent( newParentName );
270            String oid = getOid( entry );
271            String oldSchemaName = getSchemaName( oriChildName );
272            String newSchemaName = getSchemaName( newParentName );
273    
274            if ( schemaManager.getMatchingRuleRegistry().contains( oid ) )
275            {
276                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
277                    I18n.err( I18n.ERR_368, oid ) );
278            }
279    
280            Normalizer normalizer = factory.getNormalizer( schemaManager, entry, schemaManager.getRegistries(),
281                newSchemaName );
282    
283            if ( isSchemaEnabled( oldSchemaName ) )
284            {
285                schemaManager.unregisterNormalizer( oid );
286            }
287    
288            if ( isSchemaEnabled( newSchemaName ) )
289            {
290                schemaManager.add( normalizer );
291            }
292        }
293    
294    
295        private void checkOidIsUniqueForNormalizer( String oid ) throws Exception
296        {
297            if ( schemaManager.getNormalizerRegistry().contains( oid ) )
298            {
299                throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
300                    I18n.err( I18n.ERR_369, oid ) );
301            }
302        }
303    
304    
305        private void checkOidIsUniqueForNormalizer( ServerEntry entry ) throws Exception
306        {
307            String oid = getOid( entry );
308    
309            if ( schemaManager.getNormalizerRegistry().contains( oid ) )
310            {
311                throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
312                    I18n.err( I18n.ERR_369, oid ) );
313            }
314        }
315    
316    
317        private void checkNewParent( DN newParent ) throws LdapException
318        {
319            if ( newParent.size() != 3 )
320            {
321                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_370 ) );
322            }
323    
324            RDN rdn = newParent.getRdn();
325    
326            if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals(
327                SchemaConstants.OU_AT_OID ) )
328            {
329                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_371 ) );
330            }
331    
332            if ( !( ( String ) rdn.getNormValue() ).equalsIgnoreCase( SchemaConstants.NORMALIZERS_AT ) )
333            {
334                throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_372 ) );
335            }
336        }
337    }