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.api.schema.registries.synchronizers;
21
22
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26
27 import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
28 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
29 import org.apache.directory.api.ldap.model.entry.Attribute;
30 import org.apache.directory.api.ldap.model.entry.Entry;
31 import org.apache.directory.api.ldap.model.entry.Modification;
32 import org.apache.directory.api.ldap.model.entry.ModificationOperation;
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.name.Dn;
39 import org.apache.directory.api.ldap.model.name.Rdn;
40 import org.apache.directory.api.ldap.model.schema.AttributeType;
41 import org.apache.directory.api.ldap.model.schema.SchemaManager;
42 import org.apache.directory.api.ldap.model.schema.registries.Schema;
43 import org.apache.directory.api.ldap.schema.loader.SchemaEntityFactory;
44 import org.apache.directory.api.util.Strings;
45 import org.apache.directory.server.core.api.entry.ServerEntryUtils;
46 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
47 import org.apache.directory.server.i18n.I18n;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51
52
53
54
55
56
57
58
59
60
61 public class SchemaSynchronizer implements RegistrySynchronizer
62 {
63
64 private static final Logger LOG = LoggerFactory.getLogger( SchemaSynchronizer.class );
65
66 private final SchemaEntityFactory factory;
67
68 private final SchemaManager schemaManager;
69
70
71 private final AttributeType disabledAT;
72
73
74 private final AttributeType cnAT;
75
76
77 private final AttributeType dependenciesAT;
78
79
80 private final Dn ouSchemaDn;
81
82
83
84
85
86
87
88
89 public SchemaSynchronizer( SchemaManager schemaManager ) throws Exception
90 {
91 this.schemaManager = schemaManager;
92 disabledAT = schemaManager.lookupAttributeTypeRegistry( MetaSchemaConstants.M_DISABLED_AT );
93 factory = new SchemaEntityFactory();
94 cnAT = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.CN_AT );
95 dependenciesAT = schemaManager.lookupAttributeTypeRegistry( MetaSchemaConstants.M_DEPENDENCIES_AT );
96
97 ouSchemaDn = new Dn( schemaManager, SchemaConstants.OU_SCHEMA );
98 }
99
100
101
102
103
104
105
106
107
108 @Override
109 public boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean cascade )
110 throws LdapException
111 {
112 Entry entry = modifyContext.getEntry();
113 List<Modification> mods = modifyContext.getModItems();
114 boolean hasModification = SCHEMA_UNCHANGED;
115
116
117 Attribute disabledInEntry = entry.get( disabledAT );
118 Modification disabledModification = ServerEntryUtils.getModificationItem( mods, disabledAT );
119
120
121
122
123 if ( disabledModification != null )
124 {
125
126 ModificationOperation modification = disabledModification.getOperation();
127 Attribute attribute = disabledModification.getAttribute();
128
129 hasModification = modifyDisable( modifyContext, modification, attribute, disabledInEntry );
130 }
131 else if ( disabledInEntry != null )
132 {
133 hasModification = modifyDisable( modifyContext, ModificationOperation.REMOVE_ATTRIBUTE, null,
134 disabledInEntry );
135 }
136
137 return hasModification;
138 }
139
140
141
142
143
144 @Override
145 public void moveAndRename( Dn oriChildName, Dn newParentName, Rdn newRn, boolean deleteOldRn, Entry entry,
146 boolean cascaded ) throws LdapException
147 {
148
149 }
150
151
152
153
154
155
156
157
158 @Override
159 public void add( Entry entry ) throws LdapException
160 {
161 Dn dn = entry.getDn();
162 Dn parentDn = dn.getParent();
163
164 if ( !parentDn.equals( ouSchemaDn ) )
165 {
166 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_380,
167 ouSchemaDn.getName(),
168 parentDn.getName() ) );
169 }
170
171
172 boolean isEnabled = false;
173 Attribute disabled = entry.get( disabledAT );
174
175 if ( disabled == null )
176 {
177
178 isEnabled = true;
179 }
180 else if ( !disabled.contains( "TRUE" ) )
181 {
182 isEnabled = true;
183 }
184
185
186
187 checkForDependencies( isEnabled, entry );
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212 if ( isEnabled )
213 {
214 Schema schema = factory.getSchema( entry );
215 schemaManager.load( schema );
216 }
217 }
218
219
220
221
222
223
224
225
226
227
228
229 @Override
230 public void delete( Entry entry, boolean cascade ) throws LdapException
231 {
232 Attribute cn = entry.get( cnAT );
233 String schemaName = cn.getString();
234
235
236
237 Set<String> dependents = schemaManager.listDependentSchemaNames( schemaName );
238
239 if ( ( dependents != null ) && !dependents.isEmpty() )
240 {
241 String msg = I18n.err( I18n.ERR_381, dependents );
242 LOG.warn( msg );
243 throw new LdapUnwillingToPerformException(
244 ResultCodeEnum.UNWILLING_TO_PERFORM,
245 msg );
246 }
247
248
249
250 schemaManager.unload( schemaName );
251 }
252
253
254
255
256
257
258
259
260
261
262
263
264 @Override
265 public void rename( Entry entry, Rdn newRdn, boolean cascade ) throws LdapException
266 {
267 String rdnAttribute = newRdn.getNormType();
268 String rdnAttributeOid = schemaManager.getAttributeTypeRegistry().getOidByName( rdnAttribute );
269
270 if ( !rdnAttributeOid.equals( cnAT.getOid() ) )
271 {
272 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
273 I18n.err( I18n.ERR_382, rdnAttribute ) );
274 }
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340 }
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355 public void moveAndRename( Dn oriChildName, Dn newParentName, String newRdn, boolean deleteOldRdn,
356 Entry entry, boolean cascade ) throws LdapUnwillingToPerformException
357 {
358 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
359 I18n.err( I18n.ERR_383 ) );
360 }
361
362
363
364
365
366
367 @Override
368 public void move( Dn oriChildName, Dn newParentName,
369 Entry entry, boolean cascade ) throws LdapUnwillingToPerformException
370 {
371 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
372 I18n.err( I18n.ERR_383 ) );
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402 private boolean modifyDisable( ModifyOperationContext modifyContext, ModificationOperation modOp,
403 Attribute disabledInMods, Attribute disabledInEntry ) throws LdapException
404 {
405 Dn name = modifyContext.getDn();
406
407 switch ( modOp )
408 {
409
410
411
412
413 case ADD_ATTRIBUTE:
414 if ( disabledInEntry == null && "TRUE".equalsIgnoreCase( disabledInMods.getString() ) )
415 {
416 return disableSchema( getSchemaName( name ) );
417 }
418
419 break;
420
421
422
423
424
425 case REMOVE_ATTRIBUTE:
426 if ( ( disabledInEntry != null ) && ( "TRUE".equalsIgnoreCase( disabledInEntry.getString() ) ) )
427 {
428 return enableSchema( getSchemaName( name ) );
429 }
430
431 break;
432
433
434
435
436
437
438 case REPLACE_ATTRIBUTE:
439
440 boolean isCurrentlyDisabled = false;
441
442 if ( disabledInEntry != null )
443 {
444 isCurrentlyDisabled = "TRUE".equalsIgnoreCase( disabledInEntry.getString() );
445 }
446
447 boolean isNewStateDisabled = false;
448
449 if ( disabledInMods != null )
450 {
451 Value val = disabledInMods.get();
452
453 if ( val == null )
454 {
455 isNewStateDisabled = false;
456 }
457 else
458 {
459 isNewStateDisabled = "TRUE".equalsIgnoreCase( val.getString() );
460 }
461 }
462
463 if ( isCurrentlyDisabled && !isNewStateDisabled )
464 {
465 return enableSchema( getSchemaName( name ) );
466 }
467
468 if ( !isCurrentlyDisabled && isNewStateDisabled )
469 {
470 return disableSchema( getSchemaName( name ) );
471 }
472
473 break;
474
475 default:
476 throw new IllegalArgumentException( I18n.err( I18n.ERR_384, modOp ) );
477 }
478
479 return SCHEMA_UNCHANGED;
480 }
481
482
483 private String getSchemaName( Dn schema )
484 {
485 return schema.getRdn().getValue();
486 }
487
488
489 private boolean disableSchema( String schemaName ) throws LdapException
490 {
491 Schema schema = schemaManager.getLoadedSchema( schemaName );
492
493 if ( schema == null )
494 {
495
496 String msg = I18n.err( I18n.ERR_85, schemaName );
497 LOG.error( msg );
498 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
499 }
500
501 return schemaManager.disable( schemaName );
502
503 }
504
505
506
507
508
509
510 private boolean enableSchema( String schemaName ) throws LdapException
511 {
512 Schema schema = schemaManager.getLoadedSchema( schemaName );
513
514 if ( schema == null )
515 {
516
517 schemaManager.loadDisabled( schemaName );
518 }
519
520 return schemaManager.enable( schemaName );
521 }
522
523
524
525
526
527
528
529
530
531
532
533 private void checkForDependencies( boolean isEnabled, Entry entry ) throws LdapException
534 {
535 Attribute dependencies = entry.get( this.dependenciesAT );
536
537 if ( dependencies == null )
538 {
539 return;
540 }
541
542 if ( isEnabled )
543 {
544
545 Map<String, Schema> loaded = schemaManager.getRegistries().getLoadedSchemas();
546
547 for ( Value value : dependencies )
548 {
549 String dependency = value.getString();
550
551 if ( !loaded.containsKey( dependency ) )
552 {
553 throw new LdapUnwillingToPerformException(
554 ResultCodeEnum.UNWILLING_TO_PERFORM,
555 "Unwilling to perform operation on enabled schema with disabled or missing dependencies: "
556 + dependency );
557 }
558 }
559 }
560 else
561 {
562 for ( Value value : dependencies )
563 {
564 String dependency = value.getString();
565
566 if ( schemaManager.getLoadedSchema( Strings.toLowerCaseAscii( dependency ) ) == null )
567 {
568 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
569 I18n.err( I18n.ERR_385, dependency ) );
570 }
571 }
572 }
573 }
574 }