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.HashMap;
24  import java.util.HashSet;
25  import java.util.Locale;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
30  import org.apache.directory.api.ldap.model.constants.SchemaConstants;
31  import org.apache.directory.api.ldap.model.entry.Attribute;
32  import org.apache.directory.api.ldap.model.entry.Entry;
33  import org.apache.directory.api.ldap.model.entry.Value;
34  import org.apache.directory.api.ldap.model.exception.LdapException;
35  import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
36  import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
37  import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
38  import org.apache.directory.api.ldap.model.schema.AttributeType;
39  import org.apache.directory.api.ldap.model.schema.ObjectClass;
40  import org.apache.directory.api.ldap.model.schema.SchemaManager;
41  import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
42  import org.apache.directory.api.util.Strings;
43  import org.apache.directory.server.constants.ApacheSchemaConstants;
44  import org.apache.directory.server.core.api.entry.ClonedServerEntry;
45  import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
46  import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
47  import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
48  import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
49  import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
50  import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
51  import org.apache.directory.server.i18n.I18n;
52  import org.slf4j.Logger;
53  import org.slf4j.LoggerFactory;
54  
55  
56  /**
57   * Central point of control for schemas enforced by the server.  The
58   * following duties are presently performed by this class:
59   * 
60   * <ul>
61   *   <li>Provide central point of access for all registries: global and SAA specific registries</li>
62   *   <li>Manage enabling and disabling schemas</li>
63   *   <li>Responding to specific schema object changes</li>
64   * </ul>
65   *
66   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
67   */
68  public class RegistrySynchronizerAdaptor
69  {
70      /** A logger for this class */
71      private static final Logger LOG = LoggerFactory.getLogger( RegistrySynchronizerAdaptor.class );
72  
73      // indices of handlers and object ids into arrays
74      private static final int COMPARATOR_INDEX = 0;
75      private static final int NORMALIZER_INDEX = 1;
76      private static final int SYNTAX_CHECKER_INDEX = 2;
77      private static final int SYNTAX_INDEX = 3;
78      private static final int MATCHING_RULE_INDEX = 4;
79      private static final int ATTRIBUTE_TYPE_INDEX = 5;
80      private static final int OBJECT_CLASS_INDEX = 6;
81      private static final int MATCHING_RULE_USE_INDEX = 7;
82      private static final int DIT_STRUCTURE_RULE_INDEX = 8;
83      private static final int DIT_CONTENT_RULE_INDEX = 9;
84      private static final int NAME_FORM_INDEX = 10;
85  
86      private static final Set<String> VALID_OU_VALUES = new HashSet<>();
87      private static final String[] META_OBJECT_CLASSES = new String[]
88          {
89              MetaSchemaConstants.META_COMPARATOR_OC,
90              MetaSchemaConstants.META_NORMALIZER_OC,
91              MetaSchemaConstants.META_SYNTAX_CHECKER_OC,
92              MetaSchemaConstants.META_SYNTAX_OC,
93              MetaSchemaConstants.META_MATCHING_RULE_OC,
94              MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC,
95              MetaSchemaConstants.META_OBJECT_CLASS_OC,
96              MetaSchemaConstants.META_MATCHING_RULE_USE_OC,
97              MetaSchemaConstants.META_DIT_STRUCTURE_RULE_OC,
98              MetaSchemaConstants.META_DIT_CONTENT_RULE_OC,
99              MetaSchemaConstants.META_NAME_FORM_OC
100     };
101 
102     /** The SchemaManager */
103     private final SchemaManager schemaManager;
104     
105     /** The ObjectClss Attribute */
106     private final AttributeType objectClassAT;
107     
108     private final RegistrySynchronizerregistries/synchronizers/RegistrySynchronizer.html#RegistrySynchronizer">RegistrySynchronizer[] registrySynchronizers = new RegistrySynchronizer[11];
109     private final Map<String, RegistrySynchronizer> objectClass2synchronizerMap = new HashMap<>();
110     private final SchemaSynchronizer schemaSynchronizer;
111 
112     static
113     {
114         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.NORMALIZERS_AT ) );
115         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.COMPARATORS_AT ) );
116         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.SYNTAX_CHECKERS_AT ) );
117         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.SYNTAXES ) );
118         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.MATCHING_RULES_AT ) );
119         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.MATCHING_RULE_USE_AT ) );
120         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.ATTRIBUTE_TYPES_AT ) );
121         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.OBJECT_CLASSES_AT ) );
122         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.NAME_FORMS_AT ) );
123         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.DIT_CONTENT_RULES_AT ) );
124         VALID_OU_VALUES.add( Strings.toLowerCaseAscii( SchemaConstants.DIT_STRUCTURE_RULES_AT ) );
125     }
126 
127 
128     public RegistrySynchronizerAdaptor( SchemaManager schemaManager ) throws Exception
129     {
130         this.schemaManager = schemaManager;
131         this.schemaSynchronizer = new SchemaSynchronizer( schemaManager );
132         this.objectClassAT = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.OBJECT_CLASS_AT );
133 
134         this.registrySynchronizers[COMPARATOR_INDEX] = new ComparatorSynchronizer( schemaManager );
135         this.registrySynchronizers[NORMALIZER_INDEX] = new NormalizerSynchronizer( schemaManager );
136         this.registrySynchronizers[SYNTAX_CHECKER_INDEX] = new SyntaxCheckerSynchronizer( schemaManager );
137         this.registrySynchronizers[SYNTAX_INDEX] = new SyntaxSynchronizer( schemaManager );
138         this.registrySynchronizers[MATCHING_RULE_INDEX] = new MatchingRuleSynchronizer( schemaManager );
139         this.registrySynchronizers[ATTRIBUTE_TYPE_INDEX] = new AttributeTypeSynchronizer( schemaManager );
140         this.registrySynchronizers[OBJECT_CLASS_INDEX] = new ObjectClassSynchronizer( schemaManager );
141         this.registrySynchronizers[MATCHING_RULE_USE_INDEX] = new MatchingRuleUseSynchronizer( schemaManager );
142         this.registrySynchronizers[DIT_STRUCTURE_RULE_INDEX] = new DitStructureRuleSynchronizer( schemaManager );
143         this.registrySynchronizers[DIT_CONTENT_RULE_INDEX] = new DitContentRuleSynchronizer( schemaManager );
144         this.registrySynchronizers[NAME_FORM_INDEX] = new NameFormSynchronizer( schemaManager );
145 
146         ObjectClassRegistry ocReg = schemaManager.getObjectClassRegistry();
147         
148         for ( int ii = 0; ii < META_OBJECT_CLASSES.length; ii++ )
149         {
150             ObjectClass oc = ocReg.lookup( META_OBJECT_CLASSES[ii] );
151             objectClass2synchronizerMap.put( oc.getOid(), registrySynchronizers[ii] );
152         }
153     }
154 
155 
156     /**
157      * Add a new SchemaObject or a new Schema in the Schema partition.
158      *
159      * @param addContext The Add context, containing the entry to be added
160      * @throws LdapException If the addition failed
161      */
162     public void add( AddOperationContext addContext ) throws LdapException
163     {
164         Attribute oc = addContext.getEntry().get( objectClassAT );
165 
166         // First check if we are adding a schemaObject
167         for ( Value value : oc )
168         {
169 
170             String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
171 
172             if ( objectClass2synchronizerMap.containsKey( oid ) )
173             {
174                 // This is one of the eleven SchemaObject :
175                 // AT, C, DCR, DSR, MR, MRU, NF, N, OC, S, SC
176                 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
177                 Entry entry = addContext.getEntry();
178                 synchronizer.add( entry );
179 
180                 return;
181             }
182         }
183 
184         // This is a Schema
185         // e.g. ou=my custom schema,ou=schema
186         if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
187         {
188             Entry entry = addContext.getEntry();
189             schemaSynchronizer.add( entry );
190 
191             return;
192         }
193 
194         // Check if it is a valid container for AT, C, DCR, DSR, MR, MRU, NF, N, OC, S, SC
195         // e.g. ou=attributeTypes,ou=my custom schema,ou=schema
196         if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) )
197         {
198             if ( addContext.getDn().size() != 3 )
199             {
200                 String msg = I18n.err( I18n.ERR_81 );
201                 LOG.error( msg );
202                 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, msg );
203             }
204 
205             String ouValue = addContext.getDn().getRdn().getValue();
206             ouValue = Strings.toLowerCaseAscii( Strings.trim( ouValue ) );
207 
208             if ( !VALID_OU_VALUES.contains( ouValue ) )
209             {
210                 String msg = I18n.err( I18n.ERR_82, VALID_OU_VALUES );
211                 LOG.error( msg );
212                 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, msg );
213             }
214 
215             // this is a valid container.
216             return;
217         }
218 
219         String msg = I18n.err( I18n.ERR_83, addContext.getDn() );
220         LOG.error( msg );
221         throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
222     }
223 
224 
225     /**
226      * {@inheritDoc}
227      */
228     public void delete( DeleteOperationContext deleteContext, boolean doCascadeDelete )
229         throws LdapException
230     {
231         Entry entry = deleteContext.getEntry();
232 
233         Attribute oc = entry.get( objectClassAT );
234 
235         for ( Value value : oc )
236         {
237             String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
238 
239             if ( objectClass2synchronizerMap.containsKey( oid ) )
240             {
241                 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
242                 synchronizer.delete( entry, doCascadeDelete );
243                 return;
244             }
245         }
246 
247         if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
248         {
249             schemaSynchronizer.delete( entry, doCascadeDelete );
250             return;
251         }
252 
253         if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) )
254         {
255             if ( deleteContext.getDn().size() != 3 )
256             {
257                 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_378 ) );
258             }
259 
260             String ouValue = deleteContext.getDn().getRdn().getValue();
261             ouValue = Strings.toLowerCaseAscii( Strings.trim( ouValue ) );
262 
263             if ( !VALID_OU_VALUES.contains( ouValue ) )
264             {
265                 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
266                     I18n.err( I18n.ERR_379, VALID_OU_VALUES ) );
267             }
268 
269             return;
270         }
271 
272         throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
273     }
274 
275 
276     /**
277      * Modify the schema
278      *
279      * @param modifyContext The context
280      * @param targetEntry The modified entry
281      * @param doCascadeModify Not used
282      * @return <tt>true</tt> if the modify succeded
283      * @throws LdapException If the modification failed
284      */
285     public boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean doCascadeModify )
286         throws LdapException
287     {
288         Entry entry = modifyContext.getEntry();
289         Attribute oc = entry.get( objectClassAT );
290 
291         for ( Value value : oc )
292         {
293             String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
294 
295             if ( objectClass2synchronizerMap.containsKey( oid ) )
296             {
297                 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
298                 
299                 return synchronizer.modify( modifyContext, targetEntry, doCascadeModify );
300             }
301         }
302 
303         if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
304         {
305             return schemaSynchronizer.modify( modifyContext, targetEntry, doCascadeModify );
306         }
307 
308         if ( oc.contains( ApacheSchemaConstants.SCHEMA_MODIFICATION_ATTRIBUTES_OC ) )
309         {
310             return false;
311         }
312 
313         LOG.error( String.format( Locale.ROOT, I18n.err( I18n.ERR_84 ),
314             modifyContext.getDn(), entry, modifyContext.getModItems() ) );
315         throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
316     }
317 
318 
319     /**
320      * Rename a Schema Object.
321      *
322      * @param renameContext The contect contaoning the rename informations
323      * @param doCascadeModify unused
324      * @throws LdapException If the rename failed
325      */
326     public void rename( RenameOperationContext renameContext, boolean doCascadeModify )
327         throws LdapException
328     {
329         Entry originalEntry = ( ( ClonedServerEntry ) renameContext.getEntry() ).getOriginalEntry();
330         Attribute oc = originalEntry.get( objectClassAT );
331 
332         for ( Value value : oc )
333         {
334             String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
335 
336             if ( objectClass2synchronizerMap.containsKey( oid ) )
337             {
338                 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
339                 synchronizer.rename( originalEntry, renameContext.getNewRdn(), doCascadeModify );
340                 return;
341             }
342         }
343 
344         if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
345         {
346             schemaSynchronizer.rename( originalEntry, renameContext.getNewRdn(), doCascadeModify );
347             return;
348         }
349 
350         throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
351     }
352 
353 
354     /* (non-Javadoc)
355      * @see org.apache.directory.server.core.schema.SchemaChangeManager#replace(org.apache.directory.server.core.interceptor.context.MoveOperationContext, org.apache.directory.server.core.entry.Entry, boolean)
356      */
357     public void move( MoveOperationContext moveContext, Entry entry, boolean cascade ) throws LdapException
358     {
359         Attribute oc = entry.get( objectClassAT );
360 
361         for ( Value value : oc )
362         {
363             String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
364 
365             if ( objectClass2synchronizerMap.containsKey( oid ) )
366             {
367                 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
368                 synchronizer.move( moveContext.getDn(), moveContext.getNewSuperior(), entry, cascade );
369                 return;
370             }
371         }
372 
373         if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
374         {
375             schemaSynchronizer.move( moveContext.getDn(), moveContext.getNewSuperior(), entry, cascade );
376             return;
377         }
378 
379         throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
380     }
381 
382 
383     /* (non-Javadoc)
384      * @see org.apache.directory.server.core.schema.SchemaChangeManager#move(org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext, org.apache.directory.server.core.entry.Entry, boolean)
385      */
386     public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext, Entry entry, boolean cascade )
387         throws LdapException
388     {
389         Attribute oc = entry.get( objectClassAT );
390 
391         for ( Value value : oc )
392         {
393             String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
394 
395             if ( objectClass2synchronizerMap.containsKey( oid ) )
396             {
397                 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
398                 synchronizer.moveAndRename( moveAndRenameContext.getDn(), moveAndRenameContext.getNewSuperiorDn(),
399                     moveAndRenameContext.getNewRdn(),
400                     moveAndRenameContext.getDeleteOldRdn(), entry, cascade );
401                 return;
402             }
403         }
404 
405         if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
406         {
407             schemaSynchronizer.moveAndRename( moveAndRenameContext.getDn(), moveAndRenameContext.getNewSuperiorDn(),
408                 moveAndRenameContext.getNewRdn(),
409                 moveAndRenameContext.getDeleteOldRdn(), entry, cascade );
410             return;
411         }
412 
413         throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
414     }
415 }