1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.schema;
21
22
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
30 import org.apache.directory.api.ldap.model.entry.Attribute;
31 import org.apache.directory.api.ldap.model.entry.Modification;
32 import org.apache.directory.api.ldap.model.exception.LdapException;
33 import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
34 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
35 import org.apache.directory.api.ldap.model.schema.AttributeType;
36 import org.apache.directory.api.ldap.model.schema.DitContentRule;
37 import org.apache.directory.api.ldap.model.schema.DitStructureRule;
38 import org.apache.directory.api.ldap.model.schema.LdapSyntax;
39 import org.apache.directory.api.ldap.model.schema.MatchingRule;
40 import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
41 import org.apache.directory.api.ldap.model.schema.NameForm;
42 import org.apache.directory.api.ldap.model.schema.ObjectClass;
43 import org.apache.directory.api.ldap.model.schema.SchemaManager;
44 import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescription;
45 import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescription;
46 import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescription;
47 import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;
48 import org.apache.directory.api.util.Strings;
49 import org.apache.directory.server.core.api.DirectoryService;
50 import org.apache.directory.server.core.api.DnFactory;
51 import org.apache.directory.server.core.api.InterceptorEnum;
52 import org.apache.directory.server.core.api.OperationEnum;
53 import org.apache.directory.server.core.api.interceptor.Interceptor;
54 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
55 import org.apache.directory.server.core.api.schema.DescriptionParsers;
56 import org.apache.directory.server.i18n.I18n;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60
61
62
63
64
65 public class SchemaSubentryManager
66 {
67
68 private static final Logger LOG = LoggerFactory.getLogger( SchemaSubentryManager.class );
69
70
71 private static final int COMPARATOR_INDEX = 0;
72 private static final int NORMALIZER_INDEX = 1;
73 private static final int SYNTAX_CHECKER_INDEX = 2;
74 private static final int SYNTAX_INDEX = 3;
75 private static final int MATCHING_RULE_INDEX = 4;
76 private static final int ATTRIBUTE_TYPE_INDEX = 5;
77 private static final int OBJECT_CLASS_INDEX = 6;
78 private static final int MATCHING_RULE_USE_INDEX = 7;
79 private static final int DIT_STRUCTURE_RULE_INDEX = 8;
80 private static final int DIT_CONTENT_RULE_INDEX = 9;
81 private static final int NAME_FORM_INDEX = 10;
82
83 private static final Set<String> VALID_OU_VALUES = new HashSet<String>();
84
85
86 private final SchemaManager schemaManager;
87
88 private final SchemaSubentryModifier subentryModifier;
89
90
91 private final DescriptionParsers parsers;
92
93
94
95
96
97 private final Map<String, Integer> opAttr2handlerIndex = new HashMap<String, Integer>( 11 );
98 private static final String CASCADING_ERROR =
99 "Cascading has not yet been implemented: standard operation is in effect.";
100
101 private static AttributeType ENTRY_CSN_ATTRIBUTE_TYPE;
102
103 static
104 {
105 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.NORMALIZERS_AT ) );
106 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.COMPARATORS_AT ) );
107 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.SYNTAX_CHECKERS_AT ) );
108 VALID_OU_VALUES.add( Strings.toLowerCase( "syntaxes" ) );
109 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.MATCHING_RULES_AT ) );
110 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.MATCHING_RULE_USE_AT ) );
111 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.ATTRIBUTE_TYPES_AT ) );
112 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.OBJECT_CLASSES_AT ) );
113 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.NAME_FORMS_AT ) );
114 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.DIT_CONTENT_RULES_AT ) );
115 VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.DIT_STRUCTURE_RULES_AT ) );
116 }
117
118
119 public SchemaSubentryManager( SchemaManager schemaManager, SchemaLoader loader, DnFactory dnFactory )
120 throws LdapException
121 {
122 this.schemaManager = schemaManager;
123 this.subentryModifier = new SchemaSubentryModifier( schemaManager, dnFactory );
124 this.parsers = new DescriptionParsers( schemaManager );
125
126 String comparatorsOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.COMPARATORS_AT );
127 opAttr2handlerIndex.put( comparatorsOid, COMPARATOR_INDEX );
128
129 String normalizersOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.NORMALIZERS_AT );
130 opAttr2handlerIndex.put( normalizersOid, NORMALIZER_INDEX );
131
132 String syntaxCheckersOid = schemaManager.getAttributeTypeRegistry().getOidByName(
133 SchemaConstants.SYNTAX_CHECKERS_AT );
134 opAttr2handlerIndex.put( syntaxCheckersOid, SYNTAX_CHECKER_INDEX );
135
136 String ldapSyntaxesOid = schemaManager.getAttributeTypeRegistry().getOidByName(
137 SchemaConstants.LDAP_SYNTAXES_AT );
138 opAttr2handlerIndex.put( ldapSyntaxesOid, SYNTAX_INDEX );
139
140 String matchingRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName(
141 SchemaConstants.MATCHING_RULES_AT );
142 opAttr2handlerIndex.put( matchingRulesOid, MATCHING_RULE_INDEX );
143
144 String attributeTypesOid = schemaManager.getAttributeTypeRegistry().getOidByName(
145 SchemaConstants.ATTRIBUTE_TYPES_AT );
146 opAttr2handlerIndex.put( attributeTypesOid, ATTRIBUTE_TYPE_INDEX );
147
148 String objectClassesOid = schemaManager.getAttributeTypeRegistry().getOidByName(
149 SchemaConstants.OBJECT_CLASSES_AT );
150 opAttr2handlerIndex.put( objectClassesOid, OBJECT_CLASS_INDEX );
151
152 String matchingRuleUseOid = schemaManager.getAttributeTypeRegistry().getOidByName(
153 SchemaConstants.MATCHING_RULE_USE_AT );
154 opAttr2handlerIndex.put( matchingRuleUseOid, MATCHING_RULE_USE_INDEX );
155
156 String ditStructureRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName(
157 SchemaConstants.DIT_STRUCTURE_RULES_AT );
158 opAttr2handlerIndex.put( ditStructureRulesOid, DIT_STRUCTURE_RULE_INDEX );
159
160 String ditContentRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName(
161 SchemaConstants.DIT_CONTENT_RULES_AT );
162 opAttr2handlerIndex.put( ditContentRulesOid, DIT_CONTENT_RULE_INDEX );
163
164 String nameFormsOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.NAME_FORMS_AT );
165 opAttr2handlerIndex.put( nameFormsOid, NAME_FORM_INDEX );
166
167 ENTRY_CSN_ATTRIBUTE_TYPE = schemaManager.getAttributeType( SchemaConstants.ENTRY_CSN_AT );
168 }
169
170
171
172
173
174
175
176
177
178
179
180
181
182 private Interceptor findNextInterceptor( OperationEnum operation, DirectoryService directoryService )
183 {
184 Interceptor interceptor = null;
185
186 List<Interceptor> allInterceptors = directoryService.getInterceptors();
187 List<String> operationInterceptors = directoryService.getInterceptors( operation );
188 int position = 0;
189 String addInterceptor = operationInterceptors.get( position );
190
191 for ( Interceptor inter : allInterceptors )
192 {
193 String interName = inter.getName();
194
195 if ( interName.equals( InterceptorEnum.SCHEMA_INTERCEPTOR.getName() ) )
196 {
197
198 position++;
199
200 if ( position < operationInterceptors.size() )
201 {
202 interceptor = directoryService.getInterceptor( operationInterceptors.get( position ) );
203 }
204
205 break;
206 }
207
208 if ( interName.equals( addInterceptor ) )
209 {
210 position++;
211 addInterceptor = operationInterceptors.get( position );
212 }
213 }
214
215 return interceptor;
216 }
217
218
219
220
221
222 private int findPosition( OperationEnum operation, Interceptor interceptor, DirectoryService directoryService )
223 {
224 int position = 1;
225
226 List<String> interceptors = directoryService.getInterceptors( operation );
227
228 String interceptorName = interceptor.getName();
229
230 for ( String name : interceptors )
231 {
232 if ( name.equals( interceptorName ) )
233 {
234 break;
235 }
236
237 position++;
238 }
239
240 return position;
241 }
242
243
244
245
246
247 public void modifySchemaSubentry( ModifyOperationContext modifyContext, boolean doCascadeModify )
248 throws LdapException
249 {
250 DirectoryService directoryService = modifyContext.getSession().getDirectoryService();
251
252
253
254
255 Interceptor nextAdd = findNextInterceptor( OperationEnum.ADD, directoryService );
256 int positionAdd = findPosition( OperationEnum.ADD, nextAdd, directoryService );
257 Interceptor nextDelete = findNextInterceptor( OperationEnum.DELETE, directoryService );
258 int positionDelete = findPosition( OperationEnum.DELETE, nextDelete, directoryService );
259
260 for ( Modification mod : modifyContext.getModItems() )
261 {
262 String opAttrOid = schemaManager.getAttributeTypeRegistry().getOidByName( mod.getAttribute().getId() );
263
264 Attribute serverAttribute = mod.getAttribute();
265
266 switch ( mod.getOperation() )
267 {
268 case ADD_ATTRIBUTE:
269 modifyAddOperation( nextAdd, positionAdd, modifyContext, opAttrOid, serverAttribute,
270 doCascadeModify );
271 break;
272
273 case REMOVE_ATTRIBUTE:
274 modifyRemoveOperation( nextDelete, positionDelete, modifyContext, opAttrOid, serverAttribute );
275 break;
276
277 case REPLACE_ATTRIBUTE:
278
279 if ( ENTRY_CSN_ATTRIBUTE_TYPE.equals( serverAttribute.getAttributeType() ) )
280 {
281 break;
282 }
283
284 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
285 I18n.err( I18n.ERR_283 ) );
286
287 default:
288 throw new IllegalStateException( I18n.err( I18n.ERR_284, mod.getOperation() ) );
289 }
290 }
291 }
292
293
294
295
296
297
298
299
300
301
302
303 private void modifyRemoveOperation( Interceptor nextInterceptor, int position,
304 ModifyOperationContext modifyContext, String opAttrOid,
305 Attribute mods ) throws LdapException
306 {
307 int index = opAttr2handlerIndex.get( opAttrOid );
308
309 switch ( index )
310 {
311 case ( COMPARATOR_INDEX ):
312 LdapComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods );
313
314 for ( LdapComparatorDescription comparatorDescription : comparatorDescriptions )
315 {
316 subentryModifier.delete( nextInterceptor, position, modifyContext, comparatorDescription );
317 }
318
319 break;
320
321 case ( NORMALIZER_INDEX ):
322 NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods );
323
324 for ( NormalizerDescription normalizerDescription : normalizerDescriptions )
325 {
326 subentryModifier.delete( nextInterceptor, position, modifyContext, normalizerDescription );
327 }
328
329 break;
330
331 case ( SYNTAX_CHECKER_INDEX ):
332 SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods );
333
334 for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions )
335 {
336 subentryModifier.delete( nextInterceptor, position, modifyContext, syntaxCheckerDescription );
337 }
338
339 break;
340
341 case ( SYNTAX_INDEX ):
342 LdapSyntax[] syntaxes = parsers.parseLdapSyntaxes( mods );
343
344 for ( LdapSyntax syntax : syntaxes )
345 {
346 subentryModifier.deleteSchemaObject( nextInterceptor, position, modifyContext, syntax );
347 }
348
349 break;
350
351 case ( MATCHING_RULE_INDEX ):
352 MatchingRule[] mrs = parsers.parseMatchingRules( mods );
353
354 for ( MatchingRule mr : mrs )
355 {
356 subentryModifier.deleteSchemaObject( nextInterceptor, position, modifyContext, mr );
357 }
358
359 break;
360
361 case ( ATTRIBUTE_TYPE_INDEX ):
362 AttributeType[] ats = parsers.parseAttributeTypes( mods );
363
364 for ( AttributeType at : ats )
365 {
366 subentryModifier.deleteSchemaObject( nextInterceptor, position, modifyContext, at );
367 }
368
369 break;
370
371 case ( OBJECT_CLASS_INDEX ):
372 ObjectClass[] ocs = parsers.parseObjectClasses( mods );
373
374 for ( ObjectClass oc : ocs )
375 {
376 subentryModifier.deleteSchemaObject( nextInterceptor, position, modifyContext, oc );
377 }
378
379 break;
380
381 case ( MATCHING_RULE_USE_INDEX ):
382 MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods );
383
384 for ( MatchingRuleUse mru : mrus )
385 {
386 subentryModifier.deleteSchemaObject( nextInterceptor, position, modifyContext, mru );
387 }
388
389 break;
390
391 case ( DIT_STRUCTURE_RULE_INDEX ):
392 DitStructureRule[] dsrs = parsers.parseDitStructureRules( mods );
393
394 for ( DitStructureRule dsr : dsrs )
395 {
396 subentryModifier.deleteSchemaObject( nextInterceptor, position, modifyContext, dsr );
397 }
398
399 break;
400
401 case ( DIT_CONTENT_RULE_INDEX ):
402 DitContentRule[] dcrs = parsers.parseDitContentRules( mods );
403
404 for ( DitContentRule dcr : dcrs )
405 {
406 subentryModifier.deleteSchemaObject( nextInterceptor, position, modifyContext, dcr );
407 }
408
409 break;
410
411 case ( NAME_FORM_INDEX ):
412 NameForm[] nfs = parsers.parseNameForms( mods );
413
414 for ( NameForm nf : nfs )
415 {
416 subentryModifier.deleteSchemaObject( nextInterceptor, position, modifyContext, nf );
417 }
418
419 break;
420
421 default:
422 throw new IllegalStateException( I18n.err( I18n.ERR_285, index ) );
423 }
424 }
425
426
427
428
429
430
431
432
433
434
435
436
437 private void modifyAddOperation( Interceptor nextInterceptor, int position, ModifyOperationContext modifyContext,
438 String opAttrOid,
439 Attribute mods, boolean doCascadeModify ) throws LdapException
440 {
441 if ( doCascadeModify )
442 {
443 LOG.error( CASCADING_ERROR );
444 }
445
446 int index = opAttr2handlerIndex.get( opAttrOid );
447
448 switch ( index )
449 {
450 case ( COMPARATOR_INDEX ):
451 LdapComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods );
452
453 for ( LdapComparatorDescription comparatorDescription : comparatorDescriptions )
454 {
455 subentryModifier.add( nextInterceptor, position, modifyContext, comparatorDescription );
456 }
457
458 break;
459
460 case ( NORMALIZER_INDEX ):
461 NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods );
462
463 for ( NormalizerDescription normalizerDescription : normalizerDescriptions )
464 {
465 subentryModifier.add( nextInterceptor, position, modifyContext, normalizerDescription );
466 }
467
468 break;
469
470 case ( SYNTAX_CHECKER_INDEX ):
471 SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods );
472
473 for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions )
474 {
475 subentryModifier.add( nextInterceptor, position, modifyContext, syntaxCheckerDescription );
476 }
477
478 break;
479
480 case ( SYNTAX_INDEX ):
481 LdapSyntax[] syntaxes = parsers.parseLdapSyntaxes( mods );
482
483 for ( LdapSyntax syntax : syntaxes )
484 {
485 subentryModifier.addSchemaObject( nextInterceptor, position, modifyContext, syntax );
486 }
487
488 break;
489
490 case ( MATCHING_RULE_INDEX ):
491 MatchingRule[] mrs = parsers.parseMatchingRules( mods );
492
493 for ( MatchingRule mr : mrs )
494 {
495 subentryModifier.addSchemaObject( nextInterceptor, position, modifyContext, mr );
496 }
497
498 break;
499
500 case ( ATTRIBUTE_TYPE_INDEX ):
501 AttributeType[] ats = parsers.parseAttributeTypes( mods );
502
503 for ( AttributeType at : ats )
504 {
505 subentryModifier.addSchemaObject( nextInterceptor, position, modifyContext, at );
506 }
507
508 break;
509
510 case ( OBJECT_CLASS_INDEX ):
511 ObjectClass[] ocs = parsers.parseObjectClasses( mods );
512
513 for ( ObjectClass oc : ocs )
514 {
515 subentryModifier.addSchemaObject( nextInterceptor, position, modifyContext, oc );
516 }
517
518 break;
519
520 case ( MATCHING_RULE_USE_INDEX ):
521 MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods );
522
523 for ( MatchingRuleUse mru : mrus )
524 {
525 subentryModifier.addSchemaObject( nextInterceptor, position, modifyContext, mru );
526 }
527
528 break;
529
530 case ( DIT_STRUCTURE_RULE_INDEX ):
531 DitStructureRule[] dsrs = parsers.parseDitStructureRules( mods );
532
533 for ( DitStructureRule dsr : dsrs )
534 {
535 subentryModifier.addSchemaObject( nextInterceptor, position, modifyContext, dsr );
536 }
537
538 break;
539
540 case ( DIT_CONTENT_RULE_INDEX ):
541 DitContentRule[] dcrs = parsers.parseDitContentRules( mods );
542
543 for ( DitContentRule dcr : dcrs )
544 {
545 subentryModifier.addSchemaObject( nextInterceptor, position, modifyContext, dcr );
546 }
547
548 break;
549
550 case ( NAME_FORM_INDEX ):
551 NameForm[] nfs = parsers.parseNameForms( mods );
552
553 for ( NameForm nf : nfs )
554 {
555 subentryModifier.addSchemaObject( nextInterceptor, position, modifyContext, nf );
556 }
557
558 break;
559
560 default:
561 throw new IllegalStateException( I18n.err( I18n.ERR_285, index ) );
562 }
563 }
564 }