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.ArrayList;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.apache.directory.server.constants.ApacheSchemaConstants;
32 import org.apache.directory.server.constants.MetaSchemaConstants;
33 import org.apache.directory.server.core.authn.AuthenticationInterceptor;
34 import org.apache.directory.server.core.authz.AciAuthorizationInterceptor;
35 import org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor;
36 import org.apache.directory.server.core.collective.CollectiveAttributeInterceptor;
37 import org.apache.directory.server.core.entry.ClonedServerEntry;
38 import org.apache.directory.server.core.entry.DefaultServerAttribute;
39 import org.apache.directory.server.core.entry.ServerEntry;
40 import org.apache.directory.server.core.entry.ServerAttribute;
41 import org.apache.directory.server.core.entry.ServerModification;
42 import org.apache.directory.server.core.exception.ExceptionInterceptor;
43 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
44 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
45 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
46 import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
47 import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
48 import org.apache.directory.server.core.interceptor.context.OperationContext;
49 import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
50 import org.apache.directory.server.core.normalization.NormalizationInterceptor;
51 import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
52 import org.apache.directory.server.schema.registries.ObjectClassRegistry;
53 import org.apache.directory.server.schema.registries.OidRegistry;
54 import org.apache.directory.server.schema.registries.Registries;
55 import org.apache.directory.shared.ldap.NotImplementedException;
56 import org.apache.directory.shared.ldap.constants.SchemaConstants;
57 import org.apache.directory.shared.ldap.entry.EntryAttribute;
58 import org.apache.directory.shared.ldap.entry.Modification;
59 import org.apache.directory.shared.ldap.entry.ModificationOperation;
60 import org.apache.directory.shared.ldap.entry.Value;
61 import org.apache.directory.shared.ldap.exception.LdapInvalidNameException;
62 import org.apache.directory.shared.ldap.exception.LdapNamingException;
63 import org.apache.directory.shared.ldap.exception.LdapOperationNotSupportedException;
64 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
65 import org.apache.directory.shared.ldap.name.LdapDN;
66 import org.apache.directory.shared.ldap.schema.AttributeType;
67 import org.apache.directory.shared.ldap.schema.DITContentRule;
68 import org.apache.directory.shared.ldap.schema.DITStructureRule;
69 import org.apache.directory.shared.ldap.schema.MatchingRule;
70 import org.apache.directory.shared.ldap.schema.MatchingRuleUse;
71 import org.apache.directory.shared.ldap.schema.NameForm;
72 import org.apache.directory.shared.ldap.schema.ObjectClass;
73 import org.apache.directory.shared.ldap.schema.Syntax;
74 import org.apache.directory.shared.ldap.schema.syntax.AbstractSchemaDescription;
75 import org.apache.directory.shared.ldap.schema.syntax.ComparatorDescription;
76 import org.apache.directory.shared.ldap.schema.syntax.NormalizerDescription;
77 import org.apache.directory.shared.ldap.schema.syntax.SyntaxCheckerDescription;
78 import org.apache.directory.shared.ldap.util.DateUtils;
79
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
82
83 import javax.naming.NamingException;
84 import javax.naming.directory.DirContext;
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 public class SchemaOperationControl
101 {
102 private static final Logger LOG = LoggerFactory.getLogger( SchemaOperationControl.class );
103
104
105 private static final int COMPARATOR_INDEX = 0;
106 private static final int NORMALIZER_INDEX = 1;
107 private static final int SYNTAX_CHECKER_INDEX = 2;
108 private static final int SYNTAX_INDEX = 3;
109 private static final int MATCHING_RULE_INDEX = 4;
110 private static final int ATTRIBUTE_TYPE_INDEX = 5;
111 private static final int OBJECT_CLASS_INDEX = 6;
112 private static final int MATCHING_RULE_USE_INDEX = 7;
113 private static final int DIT_STRUCTURE_RULE_INDEX = 8;
114 private static final int DIT_CONTENT_RULE_INDEX = 9;
115 private static final int NAME_FORM_INDEX = 10;
116
117 private static final Set<String> VALID_OU_VALUES = new HashSet<String>();
118 private static final String[] OP_ATTRS = new String[] {
119 SchemaConstants.COMPARATORS_AT,
120 SchemaConstants.NORMALIZERS_AT,
121 SchemaConstants.SYNTAX_CHECKERS_AT,
122 SchemaConstants.LDAP_SYNTAXES_AT,
123 SchemaConstants.MATCHING_RULES_AT,
124 SchemaConstants.ATTRIBUTE_TYPES_AT,
125 SchemaConstants.OBJECT_CLASSES_AT,
126 SchemaConstants.MATCHING_RULE_USE_AT,
127 SchemaConstants.DIT_STRUCTURE_RULES_AT,
128 SchemaConstants.DIT_CONTENT_RULES_AT,
129 SchemaConstants.NAME_FORMS_AT
130 };
131 private static final String[] META_OBJECT_CLASSES = new String[] {
132 "metaComparator",
133 "metaNormalizer",
134 "metaSyntaxChecker",
135 "metaSyntax",
136 "metaMatchingRule",
137 "metaAttributeType",
138 "metaObjectClass",
139 "metaMatchingRuleUse",
140 "metaDITStructureRule",
141 "metaDITContentRule",
142 "metaNameForm"
143 };
144 private static final java.util.Collection<String> SCHEMA_MODIFICATION_ATTRIBUTES_UPDATE_BYPASS;
145
146 private final MetaSchemaHandler metaSchemaHandler;
147 private final Registries registries;
148 private final AttributeType objectClassAT;
149 private final SchemaSubentryModifier subentryModifier;
150 private final SchemaChangeHandler[] schemaObjectHandlers = new SchemaChangeHandler[11];
151
152 private final DescriptionParsers parsers;
153
154 private final Map<String, SchemaChangeHandler> opAttr2handlerMap = new HashMap<String, SchemaChangeHandler>();
155 private final Map<String, SchemaChangeHandler> objectClass2handlerMap = new HashMap<String, SchemaChangeHandler>();
156
157
158
159
160
161 private final Map<String, Integer> opAttr2handlerIndex = new HashMap<String, Integer>( 11 );
162 private static final String CASCADING_ERROR =
163 "Cascading has not yet been implemented: standard operation is in effect.";
164
165
166 static
167 {
168 VALID_OU_VALUES.add( SchemaConstants.NORMALIZERS_AT.toLowerCase() );
169 VALID_OU_VALUES.add( SchemaConstants.COMPARATORS_AT.toLowerCase() );
170 VALID_OU_VALUES.add( SchemaConstants.SYNTAX_CHECKERS_AT.toLowerCase() );
171 VALID_OU_VALUES.add( "syntaxes".toLowerCase() );
172 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULES_AT.toLowerCase() );
173 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULE_USE_AT.toLowerCase() );
174 VALID_OU_VALUES.add( SchemaConstants.ATTRIBUTE_TYPES_AT.toLowerCase() );
175 VALID_OU_VALUES.add( SchemaConstants.OBJECT_CLASSES_AT.toLowerCase() );
176 VALID_OU_VALUES.add( SchemaConstants.NAME_FORMS_AT.toLowerCase() );
177 VALID_OU_VALUES.add( SchemaConstants.DIT_CONTENT_RULES_AT.toLowerCase() );
178 VALID_OU_VALUES.add( SchemaConstants.DIT_STRUCTURE_RULES_AT.toLowerCase() );
179
180 HashSet<String> c = new HashSet<String>();
181 c.add( NormalizationInterceptor.class.getName() );
182 c.add( AuthenticationInterceptor.class.getName() );
183 c.add( AciAuthorizationInterceptor.class.getName() );
184 c.add( DefaultAuthorizationInterceptor.class.getName() );
185 c.add( ExceptionInterceptor.class.getName() );
186
187
188 c.add( SchemaInterceptor.class.getName() );
189
190 c.add( CollectiveAttributeInterceptor.class.getName() );
191
192
193 SCHEMA_MODIFICATION_ATTRIBUTES_UPDATE_BYPASS = Collections.unmodifiableCollection( c );
194 }
195
196
197 public SchemaOperationControl( Registries registries, PartitionSchemaLoader loader, SchemaPartitionDao dao )
198 throws Exception
199 {
200 this.registries = registries;
201 this.objectClassAT = this.registries.getAttributeTypeRegistry()
202 .lookup( SchemaConstants.OBJECT_CLASS_AT );
203
204 this.metaSchemaHandler = new MetaSchemaHandler( this.registries, loader );
205
206 this.schemaObjectHandlers[COMPARATOR_INDEX] = new MetaComparatorHandler( registries, loader );
207 this.schemaObjectHandlers[NORMALIZER_INDEX] = new MetaNormalizerHandler( registries, loader );
208 this.schemaObjectHandlers[SYNTAX_CHECKER_INDEX] = new MetaSyntaxCheckerHandler( registries, loader );
209 this.schemaObjectHandlers[SYNTAX_INDEX] = new MetaSyntaxHandler( registries, loader, dao );
210 this.schemaObjectHandlers[MATCHING_RULE_INDEX] = new MetaMatchingRuleHandler( registries, loader, dao );
211 this.schemaObjectHandlers[ATTRIBUTE_TYPE_INDEX] = new MetaAttributeTypeHandler( registries, loader, dao );
212 this.schemaObjectHandlers[OBJECT_CLASS_INDEX] = new MetaObjectClassHandler( registries, loader, dao );
213 this.schemaObjectHandlers[MATCHING_RULE_USE_INDEX] = new MetaMatchingRuleUseHandler( registries, loader );
214 this.schemaObjectHandlers[DIT_STRUCTURE_RULE_INDEX] = new MetaDitStructureRuleHandler( registries, loader );
215 this.schemaObjectHandlers[DIT_CONTENT_RULE_INDEX] = new MetaDitContentRuleHandler( registries, loader );
216 this.schemaObjectHandlers[NAME_FORM_INDEX] = new MetaNameFormHandler( registries, loader );
217
218 this.subentryModifier = new SchemaSubentryModifier( registries, dao );
219 this.parsers = new DescriptionParsers( registries, dao );
220
221 OidRegistry oidRegistry = registries.getOidRegistry();
222
223 String comparatorsOid = oidRegistry.getOid( SchemaConstants.COMPARATORS_AT );
224 opAttr2handlerIndex.put( comparatorsOid, COMPARATOR_INDEX );
225
226 String normalizersOid = oidRegistry.getOid( SchemaConstants.NORMALIZERS_AT );
227 opAttr2handlerIndex.put( normalizersOid, NORMALIZER_INDEX );
228
229 String syntaxCheckersOid = oidRegistry.getOid( SchemaConstants.SYNTAX_CHECKERS_AT );
230 opAttr2handlerIndex.put( syntaxCheckersOid, SYNTAX_CHECKER_INDEX );
231
232 String ldapSyntaxesOid = oidRegistry.getOid( SchemaConstants.LDAP_SYNTAXES_AT );
233 opAttr2handlerIndex.put( ldapSyntaxesOid, SYNTAX_INDEX );
234
235 String matchingRulesOid = oidRegistry.getOid( SchemaConstants.MATCHING_RULES_AT );
236 opAttr2handlerIndex.put( matchingRulesOid, MATCHING_RULE_INDEX );
237
238 String attributeTypesOid = oidRegistry.getOid( SchemaConstants.ATTRIBUTE_TYPES_AT );
239 opAttr2handlerIndex.put( attributeTypesOid, ATTRIBUTE_TYPE_INDEX );
240
241 String objectClassesOid = oidRegistry.getOid( SchemaConstants.OBJECT_CLASSES_AT );
242 opAttr2handlerIndex.put( objectClassesOid, OBJECT_CLASS_INDEX );
243
244 String matchingRuleUseOid = oidRegistry.getOid( SchemaConstants.MATCHING_RULE_USE_AT );
245 opAttr2handlerIndex.put( matchingRuleUseOid, MATCHING_RULE_USE_INDEX );
246
247 String ditStructureRulesOid = oidRegistry.getOid( SchemaConstants.DIT_STRUCTURE_RULES_AT );
248 opAttr2handlerIndex.put( ditStructureRulesOid, DIT_STRUCTURE_RULE_INDEX );
249
250 String ditContentRulesOid = oidRegistry.getOid( SchemaConstants.DIT_CONTENT_RULES_AT );
251 opAttr2handlerIndex.put( ditContentRulesOid, DIT_CONTENT_RULE_INDEX );
252
253 String nameFormsOid = oidRegistry.getOid( SchemaConstants.NAME_FORMS_AT );
254 opAttr2handlerIndex.put( nameFormsOid, NAME_FORM_INDEX );
255
256 initHandlerMaps();
257 }
258
259
260 private void initHandlerMaps() throws NamingException
261 {
262 AttributeTypeRegistry atReg = registries.getAttributeTypeRegistry();
263 for ( int ii = 0; ii < OP_ATTRS.length; ii++ )
264 {
265 AttributeType at = atReg.lookup( OP_ATTRS[ii] );
266 opAttr2handlerMap.put( at.getOid(), schemaObjectHandlers[ii] );
267 }
268
269 ObjectClassRegistry ocReg = registries.getObjectClassRegistry();
270 for ( int ii = 0; ii < META_OBJECT_CLASSES.length; ii++ )
271 {
272 ObjectClass oc = ocReg.lookup( META_OBJECT_CLASSES[ii] );
273 objectClass2handlerMap.put( oc.getOid(), schemaObjectHandlers[ii] );
274 }
275 }
276
277
278 public Registries getGlobalRegistries()
279 {
280 return registries;
281 }
282
283
284 public Registries getRegistries( LdapDN dn )
285 {
286 LOG.error( "Ignoring request for specific registries under dn {}", dn );
287 throw new NotImplementedException();
288 }
289
290
291 public void add( AddOperationContext opContext ) throws Exception
292 {
293 EntryAttribute oc = opContext.getEntry().get( objectClassAT );
294
295 for ( Value<?> value:oc )
296 {
297
298 String oid = registries.getOidRegistry().getOid( ( String ) value.get() );
299
300 if ( objectClass2handlerMap.containsKey( oid ) )
301 {
302 SchemaChangeHandler handler = objectClass2handlerMap.get( oid );
303 handler.add( opContext.getDn(), opContext.getEntry() );
304 updateSchemaModificationAttributes( opContext );
305 return;
306 }
307 }
308
309 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
310 {
311 metaSchemaHandler.add( opContext.getDn(), opContext.getEntry() );
312 updateSchemaModificationAttributes( opContext );
313 return;
314 }
315
316 if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) )
317 {
318 if ( opContext.getDn().size() != 3 )
319 {
320 throw new LdapInvalidNameException(
321 "Schema entity containers of objectClass organizationalUnit should be 3 name components in length.",
322 ResultCodeEnum.NAMING_VIOLATION );
323 }
324
325 String ouValue = ( String ) opContext.getDn().getRdn().getValue();
326 ouValue = ouValue.trim().toLowerCase();
327 if ( ! VALID_OU_VALUES.contains( ouValue ) )
328 {
329 throw new LdapInvalidNameException(
330 "Expecting organizationalUnit with one of the following names: " + VALID_OU_VALUES,
331 ResultCodeEnum.NAMING_VIOLATION );
332 }
333 return;
334 }
335
336 throw new LdapOperationNotSupportedException( ResultCodeEnum.UNWILLING_TO_PERFORM );
337 }
338
339
340 public void delete( DeleteOperationContext opContext, ClonedServerEntry entry, boolean doCascadeDelete )
341 throws Exception
342 {
343 EntryAttribute oc = entry.get( objectClassAT );
344
345 for ( Value<?> value:oc )
346 {
347 String oid = registries.getOidRegistry().getOid( ( String ) value.get() );
348
349 if ( objectClass2handlerMap.containsKey( oid ) )
350 {
351 SchemaChangeHandler handler = objectClass2handlerMap.get( oid );
352 handler.delete( opContext.getDn(), entry, doCascadeDelete );
353 updateSchemaModificationAttributes( opContext );
354 return;
355 }
356 }
357
358 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
359 {
360 metaSchemaHandler.delete( opContext.getDn(), entry, doCascadeDelete );
361 updateSchemaModificationAttributes( opContext );
362 return;
363 }
364
365 if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) )
366 {
367 if ( opContext.getDn().size() != 3 )
368 {
369 throw new LdapNamingException(
370 "Only schema entity containers of objectClass organizationalUnit with 3 name components in length" +
371 " can be deleted.", ResultCodeEnum.UNWILLING_TO_PERFORM );
372 }
373
374 String ouValue = ( String ) opContext.getDn().getRdn().getValue();
375 ouValue = ouValue.trim().toLowerCase();
376 if ( ! VALID_OU_VALUES.contains( ouValue ) )
377 {
378 throw new LdapInvalidNameException(
379 "Can only delete organizationalUnit entity containers with one of the following names: "
380 + VALID_OU_VALUES, ResultCodeEnum.NAMING_VIOLATION );
381 }
382 return;
383 }
384
385 throw new LdapOperationNotSupportedException( ResultCodeEnum.UNWILLING_TO_PERFORM );
386 }
387
388
389 public void modify( ModifyOperationContext opContext, ModificationOperation modOp, ServerEntry mods,
390 ServerEntry entry, ServerEntry targetEntry, boolean cascade ) throws Exception
391 {
392 EntryAttribute oc = entry.get( objectClassAT );
393
394 for ( Value<?> value:oc )
395 {
396 String oid = registries.getOidRegistry().getOid( ( String ) value.get() );
397
398 if ( objectClass2handlerMap.containsKey( oid ) )
399 {
400 SchemaChangeHandler handler = objectClass2handlerMap.get( oid );
401 handler.modify( opContext.getDn(), modOp, mods, entry, targetEntry, cascade );
402 updateSchemaModificationAttributes( opContext );
403 return;
404 }
405 }
406
407 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
408 {
409 metaSchemaHandler.modify( opContext.getDn(), modOp, mods, entry, targetEntry, cascade );
410 updateSchemaModificationAttributes( opContext );
411 return;
412 }
413
414 throw new LdapOperationNotSupportedException( ResultCodeEnum.UNWILLING_TO_PERFORM );
415 }
416
417
418 public void modify( ModifyOperationContext opContext, ServerEntry entry,
419 ServerEntry targetEntry, boolean doCascadeModify ) throws Exception
420 {
421 EntryAttribute oc = entry.get( objectClassAT );
422
423 for ( Value<?> value:oc )
424 {
425 String oid = registries.getOidRegistry().getOid( ( String ) value.get() );
426
427 if ( objectClass2handlerMap.containsKey( oid ) )
428 {
429 SchemaChangeHandler handler = objectClass2handlerMap.get( oid );
430 handler.modify( opContext.getDn(), opContext.getModItems(), entry, targetEntry, doCascadeModify );
431 updateSchemaModificationAttributes( opContext );
432 return;
433 }
434 }
435
436 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
437 {
438 metaSchemaHandler.modify( opContext.getDn(), opContext.getModItems(), entry, targetEntry, doCascadeModify );
439 updateSchemaModificationAttributes( opContext );
440 return;
441 }
442
443 LOG.error( String.format( "Unwilling to perform modify on %s:\n\nEntry:\n%s\n\nModifications:\n%s",
444 opContext.getDn(), entry, opContext.getModItems() ) );
445 throw new LdapOperationNotSupportedException( ResultCodeEnum.UNWILLING_TO_PERFORM );
446 }
447
448
449 public void modifyRn( RenameOperationContext opContext, ServerEntry entry, boolean doCascadeModify )
450 throws Exception
451 {
452 EntryAttribute oc = entry.get( objectClassAT );
453
454 for ( Value<?> value:oc )
455 {
456 String oid = registries.getOidRegistry().getOid( ( String ) value.get() );
457
458 if ( objectClass2handlerMap.containsKey( oid ) )
459 {
460 SchemaChangeHandler handler = objectClass2handlerMap.get( oid );
461 handler.rename( opContext.getDn(), entry, opContext.getNewRdn(), doCascadeModify );
462 updateSchemaModificationAttributes( opContext );
463 return;
464 }
465 }
466
467 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
468 {
469 metaSchemaHandler.rename( opContext.getDn(), entry, opContext.getNewRdn(), doCascadeModify );
470 updateSchemaModificationAttributes( opContext );
471 return;
472 }
473
474 throw new LdapOperationNotSupportedException( ResultCodeEnum.UNWILLING_TO_PERFORM );
475 }
476
477
478 public void replace( MoveOperationContext opContext, ServerEntry entry, boolean cascade ) throws Exception
479 {
480 EntryAttribute oc = entry.get( objectClassAT );
481
482 for ( Value<?> value:oc )
483 {
484 String oid = registries.getOidRegistry().getOid( ( String ) value.get() );
485
486 if ( objectClass2handlerMap.containsKey( oid ) )
487 {
488 SchemaChangeHandler handler = objectClass2handlerMap.get( oid );
489 handler.replace( opContext.getDn(), opContext.getParent(), entry, cascade );
490 updateSchemaModificationAttributes( opContext );
491 return;
492 }
493 }
494
495 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
496 {
497 metaSchemaHandler.replace( opContext.getDn(), opContext.getParent(), entry, cascade );
498 updateSchemaModificationAttributes( opContext );
499 return;
500 }
501
502 throw new LdapOperationNotSupportedException( ResultCodeEnum.UNWILLING_TO_PERFORM );
503 }
504
505
506 public void move( MoveAndRenameOperationContext opContext, ServerEntry entry, boolean cascade ) throws Exception
507 {
508 EntryAttribute oc = entry.get( objectClassAT );
509
510 for ( Value<?> value:oc )
511 {
512 String oid = registries.getOidRegistry().getOid( ( String ) value.get() );
513
514 if ( objectClass2handlerMap.containsKey( oid ) )
515 {
516 SchemaChangeHandler handler = objectClass2handlerMap.get( oid );
517 handler.move( opContext.getDn(), opContext.getParent(), opContext.getNewRdn(),
518 opContext.getDelOldDn(), entry, cascade );
519 updateSchemaModificationAttributes( opContext );
520 return;
521 }
522 }
523
524 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
525 {
526 metaSchemaHandler.move( opContext.getDn(), opContext.getParent(), opContext.getNewRdn(),
527 opContext.getDelOldDn(), entry, cascade );
528 updateSchemaModificationAttributes( opContext );
529 return;
530 }
531
532 throw new LdapOperationNotSupportedException( ResultCodeEnum.UNWILLING_TO_PERFORM );
533 }
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549 public void modifySchemaSubentry( ModifyOperationContext opContext,
550 ServerEntry subentry, ServerEntry targetSubentry, boolean doCascadeModify ) throws Exception
551 {
552 for ( Modification mod : opContext.getModItems() )
553 {
554 String opAttrOid = registries.getOidRegistry().getOid( mod.getAttribute().getId() );
555
556 ServerAttribute serverAttribute = (ServerAttribute)mod.getAttribute();
557
558 switch ( mod.getOperation() )
559 {
560 case ADD_ATTRIBUTE :
561
562 modifyAddOperation( opContext, opAttrOid, serverAttribute, doCascadeModify );
563 break;
564
565 case REMOVE_ATTRIBUTE :
566 modifyRemoveOperation( opContext, opAttrOid, serverAttribute, doCascadeModify );
567 break;
568
569 case REPLACE_ATTRIBUTE :
570 throw new LdapOperationNotSupportedException(
571 "Modify REPLACE operations on schema subentries are not allowed: " +
572 "it's just silly to destroy and recreate so many \nschema entities " +
573 "that reside in schema operational attributes. Instead use \na " +
574 "targeted combination of modify ADD and REMOVE operations.",
575 ResultCodeEnum.UNWILLING_TO_PERFORM );
576
577 default:
578 throw new IllegalStateException( "Undefined modify operation: " + mod.getOperation() );
579 }
580 }
581
582 if ( opContext.getModItems().size() > 0 )
583 {
584 updateSchemaModificationAttributes( opContext );
585 }
586 }
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603 public void modifySchemaSubentry( ModifyOperationContext opContext, LdapDN name, int modOp, ServerEntry mods,
604 ServerEntry subentry, ServerEntry targetSubentry, boolean doCascadeModify ) throws Exception
605 {
606 Set<AttributeType> attributeTypes = mods.getAttributeTypes();
607
608 switch ( modOp )
609 {
610 case( DirContext.ADD_ATTRIBUTE ):
611 for ( AttributeType attributeType:attributeTypes )
612 {
613 modifyAddOperation( opContext, attributeType.getOid(),
614 mods.get( attributeType ), doCascadeModify );
615 }
616
617 break;
618
619 case( DirContext.REMOVE_ATTRIBUTE ):
620 for ( AttributeType attributeType:attributeTypes )
621 {
622 modifyRemoveOperation( opContext, attributeType.getOid(),
623 mods.get( attributeType ), doCascadeModify );
624 }
625
626 break;
627
628 case( DirContext.REPLACE_ATTRIBUTE ):
629 throw new LdapOperationNotSupportedException(
630 "Modify REPLACE operations on schema subentries are not allowed: " +
631 "it's just silly to destroy and recreate so many \nschema entities " +
632 "that reside in schema operational attributes. Instead use \na " +
633 "targeted combination of modify ADD and REMOVE operations.",
634 ResultCodeEnum.UNWILLING_TO_PERFORM );
635
636 default:
637 throw new IllegalStateException( "Undefined modify operation: " + modOp );
638 }
639
640 updateSchemaModificationAttributes( opContext );
641 }
642
643
644 public String getSchema( AbstractSchemaDescription desc )
645 {
646 if ( desc.getExtensions().containsKey( MetaSchemaConstants.X_SCHEMA ) )
647 {
648 return desc.getExtensions().get( MetaSchemaConstants.X_SCHEMA ).get( 0 );
649 }
650
651 return MetaSchemaConstants.SCHEMA_OTHER;
652 }
653
654
655
656
657
658
659
660
661
662
663
664
665 private void modifyRemoveOperation( ModifyOperationContext opContext, String opAttrOid,
666 EntryAttribute mods, boolean doCascadeModify ) throws Exception
667 {
668 int index = opAttr2handlerIndex.get( opAttrOid );
669 SchemaChangeHandler handler = opAttr2handlerMap.get( opAttrOid );
670
671 switch( index )
672 {
673 case( COMPARATOR_INDEX ):
674 MetaComparatorHandler comparatorHandler = ( MetaComparatorHandler ) handler;
675 ComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods );
676
677 for ( ComparatorDescription comparatorDescription : comparatorDescriptions )
678 {
679 comparatorHandler.delete( comparatorDescription.getNumericOid(), doCascadeModify );
680 subentryModifier.delete( opContext, comparatorDescription );
681 }
682 break;
683 case( NORMALIZER_INDEX ):
684 MetaNormalizerHandler normalizerHandler = ( MetaNormalizerHandler ) handler;
685 NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods );
686
687 for ( NormalizerDescription normalizerDescription : normalizerDescriptions )
688 {
689 normalizerHandler.delete( normalizerDescription.getNumericOid(), doCascadeModify );
690 subentryModifier.delete( opContext, normalizerDescription );
691 }
692 break;
693 case( SYNTAX_CHECKER_INDEX ):
694 MetaSyntaxCheckerHandler syntaxCheckerHandler = ( MetaSyntaxCheckerHandler ) handler;
695 SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods );
696
697 for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions )
698 {
699 syntaxCheckerHandler.delete( syntaxCheckerDescription.getNumericOid(), doCascadeModify );
700 subentryModifier.delete( opContext, syntaxCheckerDescription );
701 }
702 break;
703 case( SYNTAX_INDEX ):
704 MetaSyntaxHandler syntaxHandler = ( MetaSyntaxHandler ) handler;
705 Syntax[] syntaxes = parsers.parseSyntaxes( mods );
706
707 for ( Syntax syntax : syntaxes )
708 {
709 syntaxHandler.delete( syntax, doCascadeModify );
710 subentryModifier.deleteSchemaObject( opContext, syntax );
711 }
712 break;
713 case( MATCHING_RULE_INDEX ):
714 MetaMatchingRuleHandler matchingRuleHandler = ( MetaMatchingRuleHandler ) handler;
715 MatchingRule[] mrs = parsers.parseMatchingRules( mods );
716
717 for ( MatchingRule mr : mrs )
718 {
719 matchingRuleHandler.delete( mr, doCascadeModify );
720 subentryModifier.deleteSchemaObject( opContext, mr );
721 }
722 break;
723 case( ATTRIBUTE_TYPE_INDEX ):
724 MetaAttributeTypeHandler atHandler = ( MetaAttributeTypeHandler ) handler;
725 AttributeType[] ats = parsers.parseAttributeTypes( mods );
726
727 for ( AttributeType at : ats )
728 {
729 atHandler.delete( at, doCascadeModify );
730 subentryModifier.deleteSchemaObject( opContext, at );
731 }
732 break;
733 case( OBJECT_CLASS_INDEX ):
734 MetaObjectClassHandler ocHandler = ( MetaObjectClassHandler ) handler;
735 ObjectClass[] ocs = parsers.parseObjectClasses( mods );
736
737 for ( ObjectClass oc : ocs )
738 {
739 ocHandler.delete( oc, doCascadeModify );
740 subentryModifier.deleteSchemaObject( opContext, oc );
741 }
742 break;
743 case( MATCHING_RULE_USE_INDEX ):
744 MetaMatchingRuleUseHandler mruHandler = ( MetaMatchingRuleUseHandler ) handler;
745 MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods );
746
747 for ( MatchingRuleUse mru : mrus )
748 {
749 mruHandler.delete( mru, doCascadeModify );
750 subentryModifier.deleteSchemaObject( opContext, mru );
751 }
752 break;
753 case( DIT_STRUCTURE_RULE_INDEX ):
754 MetaDitStructureRuleHandler dsrHandler = ( MetaDitStructureRuleHandler ) handler;
755 DITStructureRule[] dsrs = parsers.parseDitStructureRules( mods );
756
757 for ( DITStructureRule dsr : dsrs )
758 {
759 dsrHandler.delete( dsr, doCascadeModify );
760 subentryModifier.deleteSchemaObject( opContext, dsr );
761 }
762 break;
763 case( DIT_CONTENT_RULE_INDEX ):
764 MetaDitContentRuleHandler dcrHandler = ( MetaDitContentRuleHandler ) handler;
765 DITContentRule[] dcrs = parsers.parseDitContentRules( mods );
766
767 for ( DITContentRule dcr : dcrs )
768 {
769 dcrHandler.delete( dcr, doCascadeModify );
770 subentryModifier.deleteSchemaObject( opContext, dcr );
771 }
772 break;
773 case( NAME_FORM_INDEX ):
774 MetaNameFormHandler nfHandler = ( MetaNameFormHandler ) handler;
775 NameForm[] nfs = parsers.parseNameForms( mods );
776
777 for ( NameForm nf : nfs )
778 {
779 nfHandler.delete( nf, doCascadeModify );
780 subentryModifier.deleteSchemaObject( opContext, nf );
781 }
782 break;
783 default:
784 throw new IllegalStateException( "Unknown index into handler array: " + index );
785 }
786 }
787
788
789
790
791
792
793
794
795
796
797
798
799 private void modifyAddOperation( ModifyOperationContext opContext, String opAttrOid,
800 EntryAttribute mods, boolean doCascadeModify ) throws Exception
801 {
802 if ( doCascadeModify )
803 {
804 LOG.error( CASCADING_ERROR );
805 }
806
807 int index = opAttr2handlerIndex.get( opAttrOid );
808 SchemaChangeHandler handler = opAttr2handlerMap.get( opAttrOid );
809
810 switch( index )
811 {
812 case( COMPARATOR_INDEX ):
813 MetaComparatorHandler comparatorHandler = ( MetaComparatorHandler ) handler;
814 ComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods );
815
816 for ( ComparatorDescription comparatorDescription : comparatorDescriptions )
817 {
818 comparatorHandler.add( comparatorDescription );
819 subentryModifier.add( opContext, comparatorDescription );
820 }
821 break;
822 case( NORMALIZER_INDEX ):
823 MetaNormalizerHandler normalizerHandler = ( MetaNormalizerHandler ) handler;
824 NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods );
825
826 for ( NormalizerDescription normalizerDescription : normalizerDescriptions )
827 {
828 normalizerHandler.add( normalizerDescription );
829 subentryModifier.add( opContext, normalizerDescription );
830 }
831 break;
832 case( SYNTAX_CHECKER_INDEX ):
833 MetaSyntaxCheckerHandler syntaxCheckerHandler = ( MetaSyntaxCheckerHandler ) handler;
834 SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods );
835
836 for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions )
837 {
838 syntaxCheckerHandler.add( syntaxCheckerDescription );
839 subentryModifier.add( opContext, syntaxCheckerDescription );
840 }
841 break;
842 case( SYNTAX_INDEX ):
843 MetaSyntaxHandler syntaxHandler = ( MetaSyntaxHandler ) handler;
844 Syntax[] syntaxes = parsers.parseSyntaxes( mods );
845
846 for ( Syntax syntax : syntaxes )
847 {
848 syntaxHandler.add( syntax );
849 subentryModifier.addSchemaObject( opContext, syntax );
850 }
851 break;
852 case( MATCHING_RULE_INDEX ):
853 MetaMatchingRuleHandler matchingRuleHandler = ( MetaMatchingRuleHandler ) handler;
854 MatchingRule[] mrs = parsers.parseMatchingRules( mods );
855
856 for ( MatchingRule mr : mrs )
857 {
858 matchingRuleHandler.add( mr );
859 subentryModifier.addSchemaObject( opContext, mr );
860 }
861 break;
862 case( ATTRIBUTE_TYPE_INDEX ):
863 MetaAttributeTypeHandler atHandler = ( MetaAttributeTypeHandler ) handler;
864 AttributeType[] ats = parsers.parseAttributeTypes( mods );
865
866 for ( AttributeType at : ats )
867 {
868 atHandler.add( at );
869 subentryModifier.addSchemaObject( opContext, at );
870 }
871 break;
872 case( OBJECT_CLASS_INDEX ):
873 MetaObjectClassHandler ocHandler = ( MetaObjectClassHandler ) handler;
874 ObjectClass[] ocs = parsers.parseObjectClasses( mods );
875
876 for ( ObjectClass oc : ocs )
877 {
878 ocHandler.add( oc );
879 subentryModifier.addSchemaObject( opContext, oc );
880 }
881 break;
882 case( MATCHING_RULE_USE_INDEX ):
883 MetaMatchingRuleUseHandler mruHandler = ( MetaMatchingRuleUseHandler ) handler;
884 MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods );
885
886 for ( MatchingRuleUse mru : mrus )
887 {
888 mruHandler.add( mru );
889 subentryModifier.addSchemaObject( opContext, mru );
890 }
891 break;
892 case( DIT_STRUCTURE_RULE_INDEX ):
893 MetaDitStructureRuleHandler dsrHandler = ( MetaDitStructureRuleHandler ) handler;
894 DITStructureRule[] dsrs = parsers.parseDitStructureRules( mods );
895
896 for ( DITStructureRule dsr : dsrs )
897 {
898 dsrHandler.add( dsr );
899 subentryModifier.addSchemaObject( opContext, dsr );
900 }
901 break;
902 case( DIT_CONTENT_RULE_INDEX ):
903 MetaDitContentRuleHandler dcrHandler = ( MetaDitContentRuleHandler ) handler;
904 DITContentRule[] dcrs = parsers.parseDitContentRules( mods );
905
906 for ( DITContentRule dcr : dcrs )
907 {
908 dcrHandler.add( dcr );
909 subentryModifier.addSchemaObject( opContext, dcr );
910 }
911 break;
912 case( NAME_FORM_INDEX ):
913 MetaNameFormHandler nfHandler = ( MetaNameFormHandler ) handler;
914 NameForm[] nfs = parsers.parseNameForms( mods );
915
916 for ( NameForm nf : nfs )
917 {
918 nfHandler.add( nf );
919 subentryModifier.addSchemaObject( opContext, nf );
920 }
921 break;
922 default:
923 throw new IllegalStateException( "Unknown index into handler array: " + index );
924 }
925 }
926
927
928
929
930
931
932
933
934
935
936
937
938
939 private void updateSchemaModificationAttributes( OperationContext opContext ) throws Exception
940 {
941 String modifiersName = opContext.getSession().getEffectivePrincipal().getJndiName().getNormName();
942 String modifyTimestamp = DateUtils.getGeneralizedTime();
943
944 List<Modification> mods = new ArrayList<Modification>( 2 );
945
946 mods.add( new ServerModification( ModificationOperation.REPLACE_ATTRIBUTE,
947 new DefaultServerAttribute(
948 ApacheSchemaConstants.SCHEMA_MODIFY_TIMESTAMP_AT,
949 registries.getAttributeTypeRegistry().lookup( ApacheSchemaConstants.SCHEMA_MODIFY_TIMESTAMP_AT ),
950 modifyTimestamp ) ) );
951
952 mods.add( new ServerModification( ModificationOperation.REPLACE_ATTRIBUTE,
953 new DefaultServerAttribute(
954 ApacheSchemaConstants.SCHEMA_MODIFIERS_NAME_AT,
955 registries.getAttributeTypeRegistry().lookup( ApacheSchemaConstants.SCHEMA_MODIFIERS_NAME_AT ),
956 modifiersName ) ) );
957
958 LdapDN name = new LdapDN( "cn=schemaModifications,ou=schema" );
959 name.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
960
961 opContext.modify( name, mods, SCHEMA_MODIFICATION_ATTRIBUTES_UPDATE_BYPASS );
962 }
963 }