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<>();
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
230 break;
231
232 }
233
234 AttributeUtils.applyModification( clonedEntry, modification );
235
236 }
237
238
239 if ( reverseModifications.isEmpty() )
240 {
241 throw new IllegalArgumentException( I18n.err( I18n.ERR_12073, forwardModifications ) );
242 }
243
244
245 for ( Modification modification : reverseModifications )
246 {
247 entry.addModification( modification );
248 }
249
250
251 return entry;
252 }
253
254
255
256
257
258
259
260
261
262
263
264
265 public static LdifEntry reverseMove( Dn newSuperiorDn, Dn modifiedDn ) throws LdapException
266 {
267 LdifEntry entry = new LdifEntry();
268 Dn currentParent;
269 Rdn currentRdn;
270 Dn newDn;
271
272 if ( newSuperiorDn == null )
273 {
274 throw new IllegalArgumentException( I18n.err( I18n.ERR_12074 ) );
275 }
276
277 if ( modifiedDn == null )
278 {
279 throw new IllegalArgumentException( I18n.err( I18n.ERR_12075 ) );
280 }
281
282 if ( modifiedDn.size() == 0 )
283 {
284 throw new IllegalArgumentException( I18n.err( I18n.ERR_12076 ) );
285 }
286
287 currentParent = modifiedDn;
288 currentRdn = currentParent.getRdn();
289 currentParent = currentParent.getParent();
290
291 newDn = newSuperiorDn;
292 newDn = newDn.add( modifiedDn.getRdn() );
293
294 entry.setChangeType( ChangeType.ModDn );
295 entry.setDn( newDn );
296 entry.setNewRdn( currentRdn.getName() );
297 entry.setNewSuperior( currentParent.getName() );
298 entry.setDeleteOldRdn( false );
299 return entry;
300 }
301
302
303
304
305
306 private static LdifEntry revertEntry( Entry entry, Dn newDn, Dn newSuperior, Rdn oldRdn, Rdn newRdn )
307 throws LdapInvalidDnException
308 {
309 LdifEntry reverted = new LdifEntry();
310
311
312
313 reverted.setChangeType( ChangeType.ModRdn );
314
315 if ( newSuperior != null )
316 {
317 Dn restoredDn = newSuperior.add( newRdn );
318 reverted.setDn( restoredDn );
319 }
320 else
321 {
322 reverted.setDn( newDn );
323 }
324
325 reverted.setNewRdn( oldRdn.getName() );
326
327
328
329
330 boolean keepOldRdn = entry.contains( newRdn.getNormType(), newRdn.getNormValue() );
331
332 reverted.setDeleteOldRdn( !keepOldRdn );
333
334 if ( newSuperior != null )
335 {
336 Dn oldSuperior = entry.getDn();
337
338 oldSuperior = oldSuperior.getParent();
339 reverted.setNewSuperior( oldSuperior.getName() );
340 }
341
342 return reverted;
343 }
344
345
346
347
348
349 private static LdifEntry generateModify( Dn parentDn, Entry entry, Rdn oldRdn, Rdn newRdn )
350 {
351 LdifEntry restored = new LdifEntry();
352 restored.setChangeType( ChangeType.Modify );
353
354
355
356 restored.setDn( parentDn );
357
358 for ( Ava ava : newRdn )
359 {
360
361
362 if ( !entry.contains( ava.getNormType(), ava.getValue().getString() )
363 && !( ava.getNormType().equals( oldRdn.getNormType() ) && ava.getValue().getString().equals(
364 oldRdn.getNormValue() ) ) )
365 {
366
367 Modification modification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE,
368 new DefaultAttribute( ava.getType(), ava.getValue().getString() ) );
369
370 restored.addModification( modification );
371 }
372 }
373
374 return restored;
375 }
376
377
378
379
380
381 private static LdifEntry generateReverted( Dn newSuperior, Rdn newRdn, Dn newDn, Rdn oldRdn, boolean deleteOldRdn )
382 throws LdapInvalidDnException
383 {
384 LdifEntry reverted = new LdifEntry();
385 reverted.setChangeType( ChangeType.ModRdn );
386
387 if ( newSuperior != null )
388 {
389 Dn restoredDn = newSuperior.add( newRdn );
390 reverted.setDn( restoredDn );
391 }
392 else
393 {
394 reverted.setDn( newDn );
395 }
396
397 reverted.setNewRdn( oldRdn.getName() );
398
399 if ( newSuperior != null )
400 {
401 Dn oldSuperior = newDn;
402
403 oldSuperior = oldSuperior.getParent();
404 reverted.setNewSuperior( oldSuperior.getName() );
405 }
406
407
408 reverted.setDeleteOldRdn( deleteOldRdn );
409
410 return reverted;
411 }
412
413
414
415
416
417
418
419
420
421
422
423
424
425 public static List<LdifEntry> reverseRename( Entry entry, Rdn newRdn, boolean deleteOldRdn )
426 throws LdapInvalidDnException
427 {
428 return reverseMoveAndRename( entry, null, newRdn, deleteOldRdn );
429 }
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444 public static List<LdifEntry> reverseMoveAndRename( Entry entry, Dn newSuperior, Rdn newRdn, boolean deleteOldRdn )
445 throws LdapInvalidDnException
446 {
447 Dn parentDn = entry.getDn();
448 Dn newDn;
449
450 if ( newRdn == null )
451 {
452 throw new IllegalArgumentException( I18n.err( I18n.ERR_12077 ) );
453 }
454
455 if ( parentDn == null )
456 {
457 throw new IllegalArgumentException( I18n.err( I18n.ERR_12078 ) );
458 }
459
460 if ( parentDn.size() == 0 )
461 {
462 throw new IllegalArgumentException( I18n.err( I18n.ERR_12079 ) );
463 }
464
465 parentDn = entry.getDn();
466 Rdn oldRdn = parentDn.getRdn();
467
468 newDn = parentDn;
469 newDn = newDn.getParent();
470 newDn = newDn.add( newRdn );
471
472 List<LdifEntry> entries = new ArrayList<>( 1 );
473 LdifEntry reverted;
474
475
476 if ( newRdn.size() == 1 )
477 {
478
479 reverted = revertEntry( entry, newDn, newSuperior, oldRdn, newRdn );
480
481 entries.add( reverted );
482 }
483 else
484 {
485
486 if ( oldRdn.size() == 1 )
487 {
488
489 boolean existInEntry = false;
490
491
492
493 for ( Ava atav : newRdn )
494 {
495 if ( !atav.equals( oldRdn.getAva() )
496 && ( entry.contains( atav.getNormType(), atav.getValue().getString() ) ) )
497 {
498 existInEntry = true;
499 }
500 }
501
502
503 if ( existInEntry )
504 {
505
506
507
508 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
509
510 entries.add( reverted );
511
512
513 LdifEntry restored = generateModify( parentDn, entry, oldRdn, newRdn );
514
515 entries.add( restored );
516 }
517 else
518 {
519
520
521 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
522
523 entries.add( reverted );
524 }
525 }
526 else
527 {
528
529
530 boolean overlapping = false;
531 boolean existInEntry = false;
532
533 Set<Ava> oldAtavs = new HashSet<>();
534
535
536 for ( Ava atav : oldRdn )
537 {
538 oldAtavs.add( atav );
539 }
540
541
542
543 for ( Ava atav : newRdn )
544 {
545 if ( oldAtavs.contains( atav ) )
546 {
547 overlapping = true;
548 }
549 else if ( entry.contains( atav.getNormType(), atav.getValue().getString() ) )
550 {
551 existInEntry = true;
552 }
553 }
554
555 if ( overlapping )
556 {
557
558 if ( existInEntry )
559 {
560
561
562 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
563
564 entries.add( reverted );
565 }
566 else
567 {
568
569
570
571 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
572
573 entries.add( reverted );
574 }
575 }
576 else
577 {
578
579 if ( existInEntry )
580 {
581
582
583 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
584
585 entries.add( reverted );
586
587 LdifEntry restored = generateModify( parentDn, entry, oldRdn, newRdn );
588
589 entries.add( restored );
590 }
591 else
592 {
593
594
595 reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
596
597 entries.add( reverted );
598 }
599 }
600 }
601 }
602
603 return entries;
604 }
605 }