View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  package org.apache.directory.server.core.api.schema.registries.synchronizers;
21  
22  
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
27  import org.apache.directory.api.ldap.model.constants.SchemaConstants;
28  import org.apache.directory.api.ldap.model.entry.Entry;
29  import org.apache.directory.api.ldap.model.exception.LdapException;
30  import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
31  import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
32  import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
33  import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
34  import org.apache.directory.api.ldap.model.name.Dn;
35  import org.apache.directory.api.ldap.model.name.Rdn;
36  import org.apache.directory.api.ldap.model.schema.LdapComparator;
37  import org.apache.directory.api.ldap.model.schema.SchemaManager;
38  import org.apache.directory.api.ldap.model.schema.registries.Schema;
39  import org.apache.directory.api.util.Strings;
40  import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
41  import org.apache.directory.server.i18n.I18n;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  
46  /**
47   * A handler for operations performed to add, delete, modify, rename and 
48   * move schema comparators.
49   *
50   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
51   */
52  public class ComparatorSynchronizer extends AbstractRegistrySynchronizer
53  {
54      /** A logger for this class */
55      private static final Logger LOG = LoggerFactory.getLogger( ComparatorSynchronizer.class );
56  
57  
58      /**
59       * Creates a new instance of ComparatorSynchronizer.
60       *
61       * @param schemaManager The global schemaManager
62       * @throws Exception If the initialization failed
63       */
64      public ComparatorSynchronizer( SchemaManager schemaManager ) throws Exception
65      {
66          super( schemaManager );
67      }
68  
69  
70      /**
71       * {@inheritDoc}
72       */
73      @Override
74      public boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean cascade )
75          throws LdapException
76      {
77          Dn name = modifyContext.getDn();
78          Entry entry = modifyContext.getEntry();
79          String schemaName = getSchemaName( name );
80          String oid = getOid( entry );
81          LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, targetEntry, schemaManager
82              .getRegistries(), schemaName );
83  
84          if ( isSchemaEnabled( schemaName ) )
85          {
86              comparator.setSchemaName( schemaName );
87  
88              schemaManager.unregisterComparator( oid );
89              schemaManager.add( comparator );
90  
91              return SCHEMA_MODIFIED;
92          }
93  
94          return SCHEMA_UNCHANGED;
95      }
96  
97  
98      /**
99       * {@inheritDoc}
100      */
101     @Override
102     public void add( Entry entry ) throws LdapException
103     {
104         Dn dn = entry.getDn();
105         Dn parentDn = dn.getParent();
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(), Strings.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     @Override
150     public void delete( Entry entry, boolean cascade ) throws LdapException
151     {
152         Dn dn = entry.getDn();
153         Dn parentDn = dn.getParent();
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 = 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<>();
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(), Strings.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     @Override
228     public void rename( Entry entry, Rdn newRdn, boolean cascade ) throws LdapException
229     {
230         String oldOid = getOid( entry );
231 
232         if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) )
233         {
234             throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
235                 I18n.err( I18n.ERR_353, oldOid ) );
236         }
237 
238         String oid = newRdn.getValue();
239         checkOidIsUniqueForComparator( oid );
240 
241         String schemaName = getSchemaName( entry.getDn() );
242 
243         if ( isSchemaEnabled( schemaName ) )
244         {
245             // Inject the new OID in the entry
246             Entry targetEntry = entry.clone();
247             String newOid = newRdn.getValue();
248             checkOidIsUnique( newOid );
249             targetEntry.put( MetaSchemaConstants.M_OID_AT, newOid );
250 
251             // Inject the new Dn
252             Dn newDn = targetEntry.getDn().getParent();
253             newDn = 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     /**
266      * {@inheritDoc}
267      */
268     @Override
269     public void moveAndRename( Dn oriChildName, Dn newParentName, Rdn newRdn, boolean deleteOldRn,
270         Entry entry, boolean cascade ) throws LdapException
271     {
272         checkNewParent( newParentName );
273         String oldOid = getOid( entry );
274 
275         if ( schemaManager.getMatchingRuleRegistry().contains( oldOid ) )
276         {
277             throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
278                 I18n.err( I18n.ERR_353, oldOid ) );
279         }
280 
281         String oid = newRdn.getValue();
282         checkOidIsUniqueForComparator( oid );
283 
284         String newSchemaName = getSchemaName( newParentName );
285 
286         LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(),
287             newSchemaName );
288 
289         String oldSchemaName = getSchemaName( oriChildName );
290 
291         if ( isSchemaEnabled( oldSchemaName ) )
292         {
293             schemaManager.unregisterComparator( oldOid );
294         }
295 
296         if ( isSchemaEnabled( newSchemaName ) )
297         {
298             schemaManager.add( comparator );
299         }
300     }
301 
302 
303     /**
304      * {@inheritDoc}
305      */
306     @Override
307     public void move( Dn oriChildName, Dn newParentName, Entry entry, boolean cascade ) throws LdapException
308     {
309         checkNewParent( newParentName );
310         String oid = getOid( entry );
311 
312         if ( schemaManager.getMatchingRuleRegistry().contains( oid ) )
313         {
314             throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
315                 I18n.err( I18n.ERR_354, oid ) );
316         }
317 
318         String newSchemaName = getSchemaName( newParentName );
319 
320         LdapComparator<?> comparator = factory.getLdapComparator( schemaManager, entry, schemaManager.getRegistries(),
321             newSchemaName );
322 
323         String oldSchemaName = getSchemaName( oriChildName );
324 
325         if ( isSchemaEnabled( oldSchemaName ) )
326         {
327             schemaManager.unregisterComparator( oid );
328         }
329 
330         if ( isSchemaEnabled( newSchemaName ) )
331         {
332             schemaManager.add( comparator );
333         }
334     }
335 
336 
337     private void checkOidIsUniqueForComparator( String oid ) throws LdapSchemaViolationException
338     {
339         if ( schemaManager.getComparatorRegistry().contains( oid ) )
340         {
341             throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
342                 I18n.err( I18n.ERR_355, oid ) );
343         }
344     }
345 
346 
347     private void checkOidIsUniqueForComparator( Entry entry ) throws LdapException
348     {
349         String oid = getOid( entry );
350 
351         if ( schemaManager.getComparatorRegistry().contains( oid ) )
352         {
353             throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
354                 I18n.err( I18n.ERR_355, oid ) );
355         }
356     }
357 
358 
359     /**
360      * Check that a Comparator exists in the ComparatorRegistry, and if so,
361      * return it.
362      * 
363      * @param entry the Entry we want to know it exists
364      * @return The found comparator
365      * @throws LdapException If teh comparator is not found
366      */
367     protected LdapComparator<?> checkComparatorOidExists( Entry entry ) throws LdapException
368     {
369         String oid = getOid( entry );
370 
371         if ( schemaManager.getComparatorRegistry().contains( oid ) )
372         {
373             return schemaManager.getComparatorRegistry().get( oid );
374         }
375         else
376         {
377             throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
378                 I18n.err( I18n.ERR_336, oid ) );
379         }
380     }
381 
382 
383     private void checkNewParent( Dn newParent ) throws LdapException
384     {
385         if ( newParent.size() != 3 )
386         {
387             throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
388                 I18n.err( I18n.ERR_357 ) );
389         }
390 
391         Rdn rdn = newParent.getRdn();
392 
393         if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals(
394             SchemaConstants.OU_AT_OID ) )
395         {
396             throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_358 ) );
397         }
398 
399         if ( !rdn.getValue().equalsIgnoreCase( SchemaConstants.COMPARATORS_AT ) )
400         {
401             throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_359 ) );
402         }
403     }
404 }