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 org.apache.directory.server.constants.MetaSchemaConstants;
24 import org.apache.directory.server.core.entry.ServerAttribute;
25 import org.apache.directory.server.core.entry.ServerEntry;
26 import org.apache.directory.server.core.entry.ServerEntryUtils;
27 import org.apache.directory.server.schema.bootstrap.Schema;
28 import org.apache.directory.server.schema.registries.Registries;
29 import org.apache.directory.server.schema.registries.SchemaObjectRegistry;
30 import org.apache.directory.shared.ldap.constants.SchemaConstants;
31 import org.apache.directory.shared.ldap.entry.EntryAttribute;
32 import org.apache.directory.shared.ldap.entry.Modification;
33 import org.apache.directory.shared.ldap.entry.ModificationOperation;
34 import org.apache.directory.shared.ldap.entry.Value;
35 import org.apache.directory.shared.ldap.exception.LdapInvalidNameException;
36 import org.apache.directory.shared.ldap.exception.LdapOperationNotSupportedException;
37 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
38 import org.apache.directory.shared.ldap.name.LdapDN;
39 import org.apache.directory.shared.ldap.name.Rdn;
40 import org.apache.directory.shared.ldap.schema.AttributeType;
41 import org.apache.directory.shared.ldap.schema.SchemaObject;
42
43 import javax.naming.NamingException;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Set;
48
49
50
51
52
53
54
55
56 public class MetaSchemaHandler implements SchemaChangeHandler
57 {
58 private final SchemaEntityFactory factory;
59 private final PartitionSchemaLoader loader;
60 private final Registries globalRegistries;
61 private final AttributeType disabledAT;
62 private final String OU_OID;
63 private final AttributeType cnAT;
64 private final AttributeType dependenciesAT;
65
66
67 public MetaSchemaHandler( Registries globalRegistries, PartitionSchemaLoader loader ) throws NamingException
68 {
69 this.globalRegistries = globalRegistries;
70 this.disabledAT = globalRegistries.getAttributeTypeRegistry().lookup( MetaSchemaConstants.M_DISABLED_AT );
71 this.loader = loader;
72 this.OU_OID = globalRegistries.getOidRegistry().getOid( SchemaConstants.OU_AT );
73 this.factory = new SchemaEntityFactory( globalRegistries );
74 this.cnAT = globalRegistries.getAttributeTypeRegistry().lookup( SchemaConstants.CN_AT );
75 this.dependenciesAT = globalRegistries.getAttributeTypeRegistry()
76 .lookup( MetaSchemaConstants.M_DEPENDENCIES_AT );
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90 public void modify( LdapDN name, ModificationOperation modOp, ServerEntry mods, ServerEntry entry,
91 ServerEntry targetEntry, boolean cascade ) throws Exception
92 {
93 EntryAttribute disabledInMods = mods.get( disabledAT );
94
95 if ( disabledInMods != null )
96 {
97 disable( name, modOp, disabledInMods, entry.get( disabledAT ) );
98 }
99
100
101 boolean isEnabled = false;
102 EntryAttribute disabled = targetEntry.get( this.disabledAT );
103
104 if ( disabled == null )
105 {
106 isEnabled = true;
107 }
108 else if ( ! disabled.getString().equals( "TRUE" ) )
109 {
110 isEnabled = true;
111 }
112
113 EntryAttribute dependencies = mods.get( dependenciesAT );
114
115 if ( dependencies != null )
116 {
117 checkForDependencies( isEnabled, targetEntry );
118 }
119 }
120
121
122
123
124
125
126
127
128
129
130
131 public void modify( LdapDN name, List<Modification> mods, ServerEntry entry,
132 ServerEntry targetEntry, boolean cascade ) throws Exception
133 {
134 EntryAttribute disabledInEntry = entry.get( disabledAT );
135 Modification disabledModification = ServerEntryUtils.getModificationItem( mods, disabledAT );
136
137 if ( disabledModification != null )
138 {
139 disable( name,
140 disabledModification.getOperation(),
141 (ServerAttribute)disabledModification.getAttribute(),
142 disabledInEntry );
143 }
144
145
146 boolean isEnabled = false;
147 EntryAttribute disabled = targetEntry.get( disabledAT );
148
149 if ( disabled == null )
150 {
151 isEnabled = true;
152 }
153 else if ( ! disabled.contains( "TRUE" ) )
154 {
155 isEnabled = true;
156 }
157
158 ServerAttribute dependencies = ServerEntryUtils.getAttribute( mods, dependenciesAT );
159
160 if ( dependencies != null )
161 {
162 checkForDependencies( isEnabled, targetEntry );
163 }
164 }
165
166
167 public void move( LdapDN oriChildName, LdapDN newParentName, Rdn newRn, boolean deleteOldRn, ServerEntry entry, boolean cascaded ) throws NamingException
168 {
169
170 }
171
172
173
174
175
176
177
178
179 public void add( LdapDN name, ServerEntry entry ) throws Exception
180 {
181 LdapDN parentDn = ( LdapDN ) name.clone();
182 parentDn.remove( parentDn.size() - 1 );
183 parentDn.normalize( globalRegistries.getAttributeTypeRegistry().getNormalizerMapping() );
184 if ( !parentDn.toNormName().equals( OU_OID + "=schema" ) )
185 {
186 throw new LdapInvalidNameException( "The parent dn of a schema should be " + OU_OID + "=schema and not: "
187 + parentDn.toNormName(), ResultCodeEnum.NAMING_VIOLATION );
188 }
189
190
191 boolean isEnabled = false;
192 EntryAttribute disabled = entry.get( disabledAT );
193
194 if ( disabled == null )
195 {
196 isEnabled = true;
197 }
198 else if ( ! disabled.contains( "TRUE" ) )
199 {
200 isEnabled = true;
201 }
202
203
204
205 checkForDependencies( isEnabled, entry );
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 if ( isEnabled )
231 {
232 Schema schema = factory.getSchema( entry );
233 globalRegistries.addToLoadedSet( schema );
234 }
235 }
236
237
238
239
240
241
242
243
244
245
246 public void delete( LdapDN name, ServerEntry entry, boolean cascade ) throws Exception
247 {
248 EntryAttribute cn = entry.get( cnAT );
249 String schemaName = cn.getString();
250
251
252
253 Set<String> dependents = loader.listDependentSchemaNames( schemaName );
254 if ( ! dependents.isEmpty() )
255 {
256 throw new LdapOperationNotSupportedException(
257 "Cannot delete schema that has dependents: " + dependents,
258 ResultCodeEnum.UNWILLING_TO_PERFORM );
259 }
260
261
262
263 globalRegistries.removeFromLoadedSet( schemaName );
264 }
265
266
267
268
269
270
271
272
273
274
275
276
277 public void rename( LdapDN name, ServerEntry entry, Rdn newRdn, boolean cascade ) throws Exception
278 {
279 String rdnAttribute = newRdn.getUpType();
280 String rdnAttributeOid = globalRegistries.getOidRegistry().getOid( rdnAttribute );
281 if ( ! rdnAttributeOid.equals( cnAT.getOid() ) )
282 {
283 throw new LdapOperationNotSupportedException(
284 "Cannot allow rename with rdnAttribute set to "
285 + rdnAttribute + ": cn must be used instead." ,
286 ResultCodeEnum.UNWILLING_TO_PERFORM );
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 String schemaName = getSchemaName( name );
308 Set<String> dependents = loader.listDependentSchemaNames( schemaName );
309 if ( ! dependents.isEmpty() )
310 {
311 throw new LdapOperationNotSupportedException(
312 "Cannot allow a rename on " + schemaName + " schema while it has depentents.",
313 ResultCodeEnum.UNWILLING_TO_PERFORM );
314 }
315
316
317 boolean isEnabled = false;
318 EntryAttribute disabled = entry.get( disabledAT );
319
320 if ( disabled == null )
321 {
322 isEnabled = true;
323 }
324 else if ( ! disabled.get().equals( "TRUE" ) )
325 {
326 isEnabled = true;
327 }
328
329 if ( ! isEnabled )
330 {
331 return;
332 }
333
334
335
336
337 String newSchemaName = ( String ) newRdn.getUpValue();
338 globalRegistries.getComparatorRegistry().renameSchema( schemaName, newSchemaName );
339 globalRegistries.getNormalizerRegistry().renameSchema( schemaName, newSchemaName );
340 globalRegistries.getSyntaxCheckerRegistry().renameSchema( schemaName, newSchemaName );
341
342
343 renameSchema( globalRegistries.getAttributeTypeRegistry(), schemaName, newSchemaName );
344 renameSchema( globalRegistries.getDitContentRuleRegistry(), schemaName, newSchemaName );
345 renameSchema( globalRegistries.getDitStructureRuleRegistry(), schemaName, newSchemaName );
346 renameSchema( globalRegistries.getMatchingRuleRegistry(), schemaName, newSchemaName );
347 renameSchema( globalRegistries.getMatchingRuleUseRegistry(), schemaName, newSchemaName );
348 renameSchema( globalRegistries.getNameFormRegistry(), schemaName, newSchemaName );
349 renameSchema( globalRegistries.getObjectClassRegistry(), schemaName, newSchemaName );
350 renameSchema( globalRegistries.getSyntaxRegistry(), schemaName, newSchemaName );
351 }
352
353
354
355
356
357
358 public void move( LdapDN oriChildName, LdapDN newParentName, String newRn, boolean deleteOldRn,
359 ServerEntry entry, boolean cascade ) throws NamingException
360 {
361 throw new LdapOperationNotSupportedException( "Moving around schemas is not allowed.",
362 ResultCodeEnum.UNWILLING_TO_PERFORM );
363 }
364
365
366
367
368
369
370 public void replace( LdapDN oriChildName, LdapDN newParentName,
371 ServerEntry entry, boolean cascade ) throws NamingException
372 {
373 throw new LdapOperationNotSupportedException( "Moving around schemas is not allowed.",
374 ResultCodeEnum.UNWILLING_TO_PERFORM );
375 }
376
377
378
379
380
381
382
383 private void disable( LdapDN name, ModificationOperation modOp, EntryAttribute disabledInMods, EntryAttribute disabledInEntry )
384 throws Exception
385 {
386 switch ( modOp )
387 {
388
389
390
391
392 case ADD_ATTRIBUTE :
393 if ( disabledInEntry == null )
394 {
395 if ( "TRUE".equalsIgnoreCase( disabledInMods.getString() ) )
396 {
397 disableSchema( getSchemaName( name ) );
398 }
399 }
400
401 break;
402
403
404
405
406
407 case REMOVE_ATTRIBUTE :
408 if ( "TRUE".equalsIgnoreCase( disabledInEntry.getString() ) )
409 {
410 enableSchema( getSchemaName( name ) );
411 }
412
413 break;
414
415
416
417
418
419
420 case REPLACE_ATTRIBUTE :
421 boolean isCurrentlyDisabled = "TRUE".equalsIgnoreCase( disabledInEntry.getString() );
422 boolean isNewStateDisabled = "TRUE".equalsIgnoreCase( disabledInMods.getString() );
423
424 if ( isCurrentlyDisabled && !isNewStateDisabled )
425 {
426 enableSchema( getSchemaName( name ) );
427 break;
428 }
429
430 if ( !isCurrentlyDisabled && isNewStateDisabled )
431 {
432 disableSchema( getSchemaName( name ) );
433 }
434
435 break;
436
437 default:
438 throw new IllegalArgumentException( "Unknown modify operation type: " + modOp );
439 }
440 }
441
442
443 private String getSchemaName( LdapDN schema )
444 {
445 return ( String ) schema.getRdn().getValue();
446 }
447
448
449 private void disableSchema( String schemaName ) throws Exception
450 {
451 Set<String> dependents = loader.listEnabledDependentSchemaNames( schemaName );
452 if ( ! dependents.isEmpty() )
453 {
454 throw new LdapOperationNotSupportedException(
455 "Cannot disable schema with enabled dependents: " + dependents,
456 ResultCodeEnum.UNWILLING_TO_PERFORM );
457 }
458
459 globalRegistries.unload( schemaName );
460 }
461
462
463
464
465
466
467 private void enableSchema( String schemaName ) throws Exception
468 {
469 if ( globalRegistries.getLoadedSchemas().containsKey( schemaName ) )
470 {
471
472 return;
473 }
474
475 Schema schema = loader.getSchema( schemaName );
476 loader.loadWithDependencies( schema, globalRegistries );
477 }
478
479
480
481
482
483
484
485
486
487
488
489 private void checkForDependencies( boolean isEnabled, ServerEntry entry ) throws Exception
490 {
491 EntryAttribute dependencies = entry.get( this.dependenciesAT );
492
493 if ( dependencies == null )
494 {
495 return;
496 }
497
498 if ( isEnabled )
499 {
500
501 Map<String,Schema> loaded = globalRegistries.getLoadedSchemas();
502
503 for ( Value<?> value:dependencies )
504 {
505 String dependency = ( String ) value.get();
506
507 if ( ! loaded.containsKey( dependency ) )
508 {
509 throw new LdapOperationNotSupportedException(
510 "Unwilling to perform operation on enabled schema with disabled or missing dependencies: "
511 + dependency, ResultCodeEnum.UNWILLING_TO_PERFORM );
512 }
513 }
514 }
515 else
516 {
517 Set<String> allSchemas = loader.getSchemaNames();
518
519 for ( Value<?> value:dependencies )
520 {
521 String dependency = ( String ) value.get();
522
523 if ( ! allSchemas.contains( dependency ) )
524 {
525 throw new LdapOperationNotSupportedException(
526 "Unwilling to perform operation on schema with missing dependencies: " + dependency,
527 ResultCodeEnum.UNWILLING_TO_PERFORM );
528 }
529 }
530 }
531 }
532
533
534
535
536
537
538
539
540
541
542 private void renameSchema( SchemaObjectRegistry registry, String originalSchemaName, String newSchemaName )
543 {
544 Iterator<? extends SchemaObject> list = registry.iterator();
545 while ( list.hasNext() )
546 {
547 SchemaObject obj = list.next();
548 if ( obj.getSchema().equalsIgnoreCase( originalSchemaName ) )
549 {
550 obj.setSchema( newSchemaName );
551 }
552 }
553 }
554 }