1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.api.ldap.model.ldif;
21
22
23 import java.util.ArrayList;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Set;
27
28 import org.apache.directory.api.i18n.I18n;
29 import org.apache.directory.api.ldap.model.entry.Attribute;
30 import org.apache.directory.api.ldap.model.entry.AttributeUtils;
31 import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
32 import org.apache.directory.api.ldap.model.entry.DefaultModification;
33 import org.apache.directory.api.ldap.model.entry.Entry;
34 import org.apache.directory.api.ldap.model.entry.Modification;
35 import org.apache.directory.api.ldap.model.entry.ModificationOperation;
36 import org.apache.directory.api.ldap.model.exception.LdapException;
37 import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
38 import org.apache.directory.api.ldap.model.name.Ava;
39 import org.apache.directory.api.ldap.model.name.Dn;
40 import org.apache.directory.api.ldap.model.name.Rdn;
41
42
43
44
45
46
47
48 public final class LdifRevertor
49 {
50
51 public static final boolean DELETE_OLD_RDN = true;
52
53
54 public static final boolean KEEP_OLD_RDN = false;
55
56
57
58
59
60 private LdifRevertor()
61 {
62 }
63
64
65
66
67
68
69
70
71
72 public static LdifEntry reverseAdd( Dn dn )
73 {
74 LdifEntry entry = new LdifEntry();
75 entry.setChangeType( ChangeType.Delete );
76 entry.setDn( dn );
77 return entry;
78 }
79
80
81
82
83
84
85
86
87
88
89
90 public static LdifEntry reverseDel( Dn dn, Entry deletedEntry ) throws LdapException
91 {
92 LdifEntry entry = new LdifEntry();
93
94 entry.setDn( dn );
95 entry.setChangeType( ChangeType.Add );
96
97 for ( Attribute attribute : deletedEntry )
98 {
99 entry.addAttribute( attribute );
100 }
101
102 return entry;
103 }
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 public static LdifEntry reverseModify( Dn dn, List<Modification> forwardModifications, Entry modifiedEntry )
127 throws LdapException
128 {
129
130 Entry clonedEntry = modifiedEntry.clone();
131
132 LdifEntry entry = new LdifEntry();
133 entry.setChangeType( ChangeType.Modify );
134
135 entry.setDn( dn );
136
137
138
139 List<Modification> reverseModifications = new ArrayList<Modification>();
140
141
142
143
144 for ( Modification modification : forwardModifications )
145 {
146 switch ( modification.getOperation() )
147 {
148 case ADD_ATTRIBUTE:
149 Attribute mod = modification.getAttribute();
150
151 Attribute previous = clonedEntry.get( mod.getId() );
152
153 if ( mod.equals( previous ) )
154 {
155 continue;
156 }
157
158 Modification reverseModification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE,
159 mod );
160 reverseModifications.add( 0, reverseModification );
161 break;
162
163 case REMOVE_ATTRIBUTE:
164 mod = modification.getAttribute();
165
166 previous = clonedEntry.get( mod.getId() );
167
168 if ( previous == null )
169 {
170
171 continue;
172 }
173
174 if ( mod.get() == null )
175 {
176 reverseModification = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, previous );
177 reverseModifications.add( 0, reverseModification );
178 break;
179 }
180
181 reverseModification = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, mod );
182 reverseModifications.add( 0, reverseModification );
183 break;
184
185 case REPLACE_ATTRIBUTE:
186 mod = modification.getAttribute();
187
188 previous = clonedEntry.get( mod.getId() );
189
190
191
192
193
194
195
196
197
198
199 if ( ( mod.get() == null ) && ( previous == null ) )
200 {
201 reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
202 new DefaultAttribute( mod.getId() ) );
203 reverseModifications.add( 0, reverseModification );
204 continue;
205 }
206
207 if ( mod.get() == null )
208 {
209 reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
210 previous );
211 reverseModifications.add( 0, reverseModification );
212 continue;
213 }
214
215 if ( previous == null )
216 {
217 Attribute emptyAttribute = new DefaultAttribute( mod.getId() );
218 reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
219 emptyAttribute );
220 reverseModifications.add( 0, reverseModification );
221 continue;
222 }
223
224 reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, previous );
225 reverseModifications.add( 0, reverseModification );
226 break;
227
228 default:
229 break;
230
231 }
232
233 AttributeUtils.applyModification( clonedEntry, modification );
234
235 }
236
237
238 if ( reverseModifications.size() == 0 )
239 {
240 throw new IllegalArgumentException( I18n.err( I18n.ERR_12073, forwardModifications ) );
241 }
242
243
244 for ( Modification modification : reverseModifications )
245 {
246 entry.addModification( modification );
247 }
248
249
250 return entry;
251 }
252
253
254
255
256
257
258
259
260
261
262
263
264 public static LdifEntry reverseMove( Dn newSuperiorDn, Dn modifiedDn ) throws LdapException
265 {
266 LdifEntry entry = new LdifEntry();
267 Dn currentParent = null;
268 Rdn currentRdn = null;
269 Dn newDn = null;
270
271 if ( newSuperiorDn == null )
272 {
273 throw new IllegalArgumentException( I18n.err( I18n.ERR_12074 ) );
274 }
275
276 if ( modifiedDn == null )
277 {
278 throw new IllegalArgumentException( I18n.err( I18n.ERR_12075 ) );
279 }
280
281 if ( modifiedDn.size() == 0 )
282 {
283 throw new IllegalArgumentException( I18n.err( I18n.ERR_12076 ) );
284 }
285
286 currentParent = modifiedDn;
287 currentRdn = currentParent.getRdn();
288 currentParent = currentParent.getParent();
289
290 newDn = newSuperiorDn;
291 newDn = newDn.add( modifiedDn.getRdn() );
292
293 entry.setChangeType( ChangeType.ModDn );
294 entry.setDn( newDn );
295 entry.setNewRdn( currentRdn.getName() );
296 entry.setNewSuperior( currentParent.getName() );
297 entry.setDeleteOldRdn( false );
298 return entry;
299 }
300
301
302
303
304
305 private static LdifEntry revertEntry( Entry entry, Dn newDn, Dn newSuperior, Rdn oldRdn, Rdn newRdn )
306 throws LdapInvalidDnException
307 {
308 LdifEntry reverted = new LdifEntry();
309
310
311
312 reverted.setChangeType( ChangeType.ModRdn );
313
314 if ( newSuperior != null )
315 {
316 Dn restoredDn = newSuperior.add( newRdn );
317 reverted.setDn( restoredDn );
318 }
319 else
320 {
321 reverted.setDn( newDn );
322 }
323
324 reverted.setNewRdn( oldRdn.getName() );
325
326
327
328
329 boolean keepOldRdn = entry.contains( newRdn.getNormType(), newRdn.getNormValue() );
330
331 reverted.setDeleteOldRdn( !keepOldRdn );
332
333 if ( newSuperior != null )
334 {
335 Dn oldSuperior = entry.getDn();
336
337 oldSuperior = oldSuperior.getParent();
338 reverted.setNewSuperior( oldSuperior.getName() );
339 }
340
341 return reverted;
342 }
343
344
345
346
347
348 private static LdifEntry generateModify( Dn parentDn, Entry entry, Rdn oldRdn, Rdn newRdn )
349 {
350 LdifEntry restored = new LdifEntry();
351 restored.setChangeType( ChangeType.Modify );
352
353
354
355 restored.setDn( parentDn );
356
357 for ( Ava ava : newRdn )
358 {
359
360
361 if ( !entry.contains( ava.getNormType(), ava.getNormValue().getString() )
362 && !( ava.getNormType().equals( oldRdn.getNormType() ) && ava.getNormValue().getString().equals(
363 oldRdn.getNormValue().getString() ) ) )
364 {
365
366 Modification modification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE,
367 new DefaultAttribute( ava.getType(), ava.getValue().getString() ) );
368
369 restored.addModification( modification );
370 }
371 }
372
373 return restored;
374 }
375
376
377
378
379
380 private static LdifEntry generateReverted( Dn newSuperior, Rdn newRdn, Dn newDn, Rdn oldRdn, boolean deleteOldRdn )
381 throws LdapInvalidDnException
382 {
383 LdifEntry reverted = new LdifEntry();
384 reverted.setChangeType( ChangeType.ModRdn );
385
386 if ( newSuperior != null )
387 {
388 Dn restoredDn = newSuperior.add( newRdn );
389 reverted.setDn( restoredDn );
390 }
391 else
392 {
393 reverted.setDn( newDn );
394 }
395
396 reverted.setNewRdn( oldRdn.getName() );
397
398 if ( newSuperior != null )
399 {
400 Dn oldSuperior = newDn;
401
402 oldSuperior = oldSuperior.getParent();
403 reverted.setNewSuperior( oldSuperior.getName() );
404 }
405
406
407 reverted.setDeleteOldRdn( deleteOldRdn );
408
409 return reverted;
410 }
411
412
413
414
415
416
417
418
419
420
421
422
423
424 public static List<LdifEntry> reverseRename( Entry entry, Rdn newRdn, boolean deleteOldRdn )
425 throws LdapInvalidDnException
426 {
427 return reverseMoveAndRename( entry, null, newRdn, deleteOldRdn );
428 }
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443 public static List<LdifEntry> reverseMoveAndRename( Entry entry, Dn newSuperior, Rdn newRdn, boolean deleteOldRdn )
444 throws LdapInvalidDnException
445 {
446 Dn parentDn = entry.getDn();
447 Dn newDn = null;
448
449 if ( newRdn == null )
450 {
451 throw new IllegalArgumentException( I18n.err( I18n.ERR_12077 ) );
452 }
453
454 if ( parentDn == null )
455 {
456 throw new IllegalArgumentException( I18n.err( I18n.ERR_12078 ) );
457 }
458
459 if ( parentDn.size() == 0 )
460 {
461 throw new IllegalArgumentException( I18n.err( I18n.ERR_12079 ) );
462 }
463
464 parentDn = entry.getDn();
465 Rdn oldRdn = parentDn.getRdn();
466
467 newDn = parentDn;
468 newDn = newDn.getParent();
469 newDn = newDn.add( newRdn );
470
471 List<LdifEntry> entries = new ArrayList<LdifEntry>( 1 );
472 LdifEntry reverted = new LdifEntry();
473
474
475 if ( newRdn.size() == 1 )
476 {
477
478 reverted = revertEntry( entry, newDn, newSuperior, oldRdn, newRdn );
479
480 entries.add( reverted );
481 }
482 else
483 {
484
485 if ( oldRdn.size() == 1 )
486 {
487
488 boolean overlapping = false;
489 boolean existInEntry = false;
490
491
492
493 for ( Ava atav : newRdn )
494 {
495 if ( atav.equals( oldRdn.getAva() ) )
496 {
497
498 overlapping = true;
499 }
500 else
501 {
502 if ( entry.contains( atav.getNormType(), atav.getNormValue().getString() ) )
503 {
504 existInEntry = true;
505 }
506 }
507 }
508
509 if ( overlapping )
510 {
511
512 if ( existInEntry )
513 {
514
515
516
517 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
518
519 entries.add( reverted );
520
521
522 LdifEntry restored = generateModify( parentDn, entry, oldRdn, newRdn );
523
524 entries.add( restored );
525 }
526 else
527 {
528
529
530 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
531
532 entries.add( reverted );
533 }
534 }
535 else
536 {
537 if ( existInEntry )
538 {
539
540
541
542 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
543
544 entries.add( reverted );
545
546 LdifEntry restored = generateModify( parentDn, entry, oldRdn, newRdn );
547
548 entries.add( restored );
549 }
550 else
551 {
552
553 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
554
555 entries.add( reverted );
556 }
557 }
558 }
559 else
560 {
561
562
563 boolean overlapping = false;
564 boolean existInEntry = false;
565
566 Set<Ava> oldAtavs = new HashSet<Ava>();
567
568
569 for ( Ava atav : oldRdn )
570 {
571 oldAtavs.add( atav );
572 }
573
574
575
576 for ( Ava atav : newRdn )
577 {
578 if ( oldAtavs.contains( atav ) )
579 {
580 overlapping = true;
581 }
582 else if ( entry.contains( atav.getNormType(), atav.getNormValue().getString() ) )
583 {
584 existInEntry = true;
585 }
586 }
587
588 if ( overlapping )
589 {
590
591 if ( existInEntry )
592 {
593
594
595 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
596
597 entries.add( reverted );
598 }
599 else
600 {
601
602
603
604 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
605
606 entries.add( reverted );
607 }
608 }
609 else
610 {
611
612 if ( existInEntry )
613 {
614
615
616 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
617
618 entries.add( reverted );
619
620 LdifEntry restored = generateModify( parentDn, entry, oldRdn, newRdn );
621
622 entries.add( restored );
623 }
624 else
625 {
626
627
628 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
629
630 entries.add( reverted );
631 }
632 }
633 }
634 }
635
636 return entries;
637 }
638 }