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.io.IOException;
24 import java.io.UnsupportedEncodingException;
25
26 import javax.naming.directory.Attributes;
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.Entry;
33 import org.apache.directory.api.ldap.model.entry.Modification;
34 import org.apache.directory.api.ldap.model.entry.Value;
35 import org.apache.directory.api.ldap.model.exception.LdapException;
36 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
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.util.Base64;
40 import org.apache.directory.api.util.Strings;
41
42
43
44
45
46
47
48 public final class LdifUtils
49 {
50
51 private static final boolean[] LDIF_SAFE_STARTING_CHAR_ALPHABET = new boolean[128];
52
53
54 private static final boolean[] LDIF_SAFE_OTHER_CHARS_ALPHABET = new boolean[128];
55
56
57 private static final int DEFAULT_LINE_LENGTH = 80;
58
59
60 private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
61
62 static
63 {
64
65 for ( int i = 0; i < 128; i++ )
66 {
67 LDIF_SAFE_STARTING_CHAR_ALPHABET[i] = true;
68 }
69
70 LDIF_SAFE_STARTING_CHAR_ALPHABET[0] = false;
71 LDIF_SAFE_STARTING_CHAR_ALPHABET[10] = false;
72 LDIF_SAFE_STARTING_CHAR_ALPHABET[13] = false;
73 LDIF_SAFE_STARTING_CHAR_ALPHABET[32] = false;
74 LDIF_SAFE_STARTING_CHAR_ALPHABET[58] = false;
75 LDIF_SAFE_STARTING_CHAR_ALPHABET[60] = false;
76
77
78 for ( int i = 0; i < 128; i++ )
79 {
80 LDIF_SAFE_OTHER_CHARS_ALPHABET[i] = true;
81 }
82
83 LDIF_SAFE_OTHER_CHARS_ALPHABET[0] = false;
84 LDIF_SAFE_OTHER_CHARS_ALPHABET[10] = false;
85 LDIF_SAFE_OTHER_CHARS_ALPHABET[13] = false;
86 }
87
88
89
90
91
92 private LdifUtils()
93 {
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 public static boolean isLDIFSafe( String str )
128 {
129 if ( Strings.isEmpty( str ) )
130 {
131
132 return true;
133 }
134
135
136 char currentChar = str.charAt( 0 );
137
138 if ( ( currentChar > 127 ) || !LDIF_SAFE_STARTING_CHAR_ALPHABET[currentChar] )
139 {
140 return false;
141 }
142
143
144 for ( int i = 1; i < str.length(); i++ )
145 {
146 currentChar = str.charAt( i );
147
148 if ( ( currentChar > 127 ) || !LDIF_SAFE_OTHER_CHARS_ALPHABET[currentChar] )
149 {
150 return false;
151 }
152 }
153
154
155 return ( currentChar != ' ' );
156 }
157
158
159
160
161
162
163
164
165
166 public static String convertToLdif( Attributes attrs ) throws LdapException
167 {
168 return convertAttributesToLdif( AttributeUtils.toEntry( attrs, null ), DEFAULT_LINE_LENGTH );
169 }
170
171
172
173
174
175
176
177
178
179
180 public static String convertToLdif( Attributes attrs, int length ) throws LdapException
181 {
182 return convertAttributesToLdif( AttributeUtils.toEntry( attrs, null ), length );
183 }
184
185
186
187
188
189
190
191
192
193
194
195 public static String convertToLdif( Attributes attrs, Dn dn, int length ) throws LdapException
196 {
197 return convertToLdif( AttributeUtils.toEntry( attrs, dn ), length );
198 }
199
200
201
202
203
204
205
206
207
208
209 public static String convertToLdif( Attributes attrs, Dn dn ) throws LdapException
210 {
211 return convertToLdif( AttributeUtils.toEntry( attrs, dn ), DEFAULT_LINE_LENGTH );
212 }
213
214
215
216
217
218
219
220
221
222 public static String convertToLdif( Entry entry ) throws LdapException
223 {
224 return convertToLdif( entry, DEFAULT_LINE_LENGTH );
225 }
226
227
228
229
230
231
232
233
234
235
236 public static String convertToLdif( Entry entry, boolean includeVersionInfo ) throws LdapException
237 {
238 String ldif = convertToLdif( entry, DEFAULT_LINE_LENGTH );
239
240 if ( includeVersionInfo )
241 {
242 ldif = "version: 1" + LINE_SEPARATOR + ldif;
243 }
244
245 return ldif;
246 }
247
248
249
250
251
252
253
254
255
256 public static String convertAttributesToLdif( Entry entry ) throws LdapException
257 {
258 return convertAttributesToLdif( entry, DEFAULT_LINE_LENGTH );
259 }
260
261
262
263
264
265
266
267
268
269 public static Attributes getJndiAttributesFromLdif( String ldif ) throws LdapLdifException
270 {
271 LdifAttributesReader reader = new LdifAttributesReader();
272
273 try
274 {
275 Attributes attributes = AttributeUtils.toAttributes( reader.parseEntry( ldif ) );
276
277 reader.close();
278
279 return attributes;
280 }
281 catch ( IOException ioe )
282 {
283 throw new LdapLdifException( ioe.getMessage() );
284 }
285 }
286
287
288
289
290
291
292
293
294
295
296 public static String convertToLdif( Entry entry, int length ) throws LdapException
297 {
298 StringBuilder sb = new StringBuilder();
299
300 if ( entry.getDn() != null )
301 {
302
303 if ( isLDIFSafe( entry.getDn().getName() ) )
304 {
305 sb.append( stripLineToNChars( "dn: " + entry.getDn().getName(), length ) );
306 }
307 else
308 {
309 sb.append( stripLineToNChars( "dn:: " + encodeBase64( entry.getDn().getName() ), length ) );
310 }
311
312 sb.append( '\n' );
313 }
314
315
316 for ( Attribute attribute : entry )
317 {
318 sb.append( convertToLdif( attribute, length ) );
319 }
320
321 return sb.toString();
322 }
323
324
325
326
327
328
329
330
331
332
333 public static String convertAttributesToLdif( Entry entry, int length ) throws LdapException
334 {
335 StringBuilder sb = new StringBuilder();
336
337
338 for ( Attribute attribute : entry )
339 {
340 sb.append( convertToLdif( attribute, length ) );
341 }
342
343 return sb.toString();
344 }
345
346
347
348
349
350
351
352
353
354 public static String convertToLdif( LdifEntry entry ) throws LdapException
355 {
356 return convertToLdif( entry, DEFAULT_LINE_LENGTH );
357 }
358
359
360
361
362
363
364
365
366
367
368 public static String convertToLdif( LdifEntry entry, int length ) throws LdapException
369 {
370 StringBuilder sb = new StringBuilder();
371
372
373 if ( isLDIFSafe( entry.getDn().getName() ) )
374 {
375 sb.append( stripLineToNChars( "dn: " + entry.getDn(), length ) );
376 }
377 else
378 {
379 sb.append( stripLineToNChars( "dn:: " + encodeBase64( entry.getDn().getName() ), length ) );
380 }
381
382 sb.append( '\n' );
383
384
385 String changeType = Strings.toLowerCase( entry.getChangeType().toString() );
386
387 if ( entry.getChangeType() != ChangeType.None )
388 {
389
390 if ( entry.hasControls() )
391 {
392 for ( LdifControl control : entry.getControls().values() )
393 {
394 StringBuilder controlStr = new StringBuilder();
395
396 controlStr.append( "control: " ).append( control.getOid() );
397 controlStr.append( " " ).append( control.isCritical() );
398
399 if ( control.hasValue() )
400 {
401 controlStr.append( "::" ).append( Base64.encode( control.getValue() ) );
402 }
403
404 sb.append( stripLineToNChars( controlStr.toString(), length ) );
405 sb.append( '\n' );
406 }
407 }
408
409 sb.append( stripLineToNChars( "changetype: " + changeType, length ) );
410 sb.append( '\n' );
411 }
412
413 switch ( entry.getChangeType() )
414 {
415 case None:
416 if ( entry.hasControls() )
417 {
418 sb.append( stripLineToNChars( "changetype: " + ChangeType.Add, length ) );
419 }
420
421
422
423 case Add:
424 if ( ( entry.getEntry() == null ) )
425 {
426 throw new LdapException( I18n.err( I18n.ERR_12082 ) );
427 }
428
429
430 for ( Attribute attribute : entry.getEntry() )
431 {
432 sb.append( convertToLdif( attribute, length ) );
433 }
434
435 break;
436
437 case Delete:
438 if ( entry.getEntry() != null )
439 {
440 throw new LdapException( I18n.err( I18n.ERR_12081 ) );
441 }
442
443 break;
444
445 case ModDn:
446 case ModRdn:
447 if ( entry.getEntry() != null )
448 {
449 throw new LdapException( I18n.err( I18n.ERR_12083 ) );
450 }
451
452
453 Attribute newRdn = new DefaultAttribute( "newrdn", entry.getNewRdn() );
454 sb.append( convertToLdif( newRdn, length ) );
455
456
457 sb.append( "deleteoldrdn: " );
458
459 if ( entry.isDeleteOldRdn() )
460 {
461 sb.append( "1" );
462 }
463 else
464 {
465 sb.append( "0" );
466 }
467
468 sb.append( '\n' );
469
470
471 if ( !Strings.isEmpty( entry.getNewSuperior() ) )
472 {
473 Attribute newSuperior = new DefaultAttribute( "newsuperior", entry.getNewSuperior() );
474 sb.append( convertToLdif( newSuperior, length ) );
475 }
476
477 break;
478
479 case Modify:
480 for ( Modification modification : entry.getModifications() )
481 {
482 switch ( modification.getOperation() )
483 {
484 case ADD_ATTRIBUTE:
485 sb.append( "add: " );
486 break;
487
488 case REMOVE_ATTRIBUTE:
489 sb.append( "delete: " );
490 break;
491
492 case REPLACE_ATTRIBUTE:
493 sb.append( "replace: " );
494 break;
495 }
496
497 sb.append( modification.getAttribute().getUpId() );
498 sb.append( '\n' );
499
500 sb.append( convertToLdif( modification.getAttribute() ) );
501 sb.append( "-\n" );
502 }
503
504 break;
505 }
506
507 sb.append( '\n' );
508
509 return sb.toString();
510 }
511
512
513
514
515
516
517
518
519 private static String encodeBase64( String str )
520 {
521 char[] encoded = null;
522
523 try
524 {
525
526 encoded = Base64.encode( str.getBytes( "UTF-8" ) );
527 }
528 catch ( UnsupportedEncodingException e )
529 {
530 encoded = Base64.encode( str.getBytes() );
531 }
532
533 return new String( encoded );
534 }
535
536
537
538
539
540
541
542
543
544 public static String convertToLdif( Attribute attr ) throws LdapException
545 {
546 return convertToLdif( attr, DEFAULT_LINE_LENGTH );
547 }
548
549
550
551
552
553
554
555
556
557
558 public static String convertToLdif( Attribute attr, int length ) throws LdapException
559 {
560 StringBuilder sb = new StringBuilder();
561
562 for ( Value<?> value : attr )
563 {
564 StringBuilder lineBuffer = new StringBuilder();
565
566 lineBuffer.append( attr.getUpId() );
567
568
569 if ( value.isNull() )
570 {
571 lineBuffer.append( ':' );
572 }
573 else if ( value.isHumanReadable() )
574 {
575
576 String str = value.getString();
577
578 if ( !LdifUtils.isLDIFSafe( str ) )
579 {
580 lineBuffer.append( ":: " + encodeBase64( str ) );
581 }
582 else
583 {
584 lineBuffer.append( ":" );
585
586 if ( str != null )
587 {
588 lineBuffer.append( " " ).append( str );
589 }
590 }
591 }
592 else
593 {
594
595 char[] encoded = Base64.encode( value.getBytes() );
596
597 lineBuffer.append( ":: " + new String( encoded ) );
598 }
599
600 lineBuffer.append( "\n" );
601 sb.append( stripLineToNChars( lineBuffer.toString(), length ) );
602 }
603
604 return sb.toString();
605 }
606
607
608
609
610
611
612
613
614
615 public static String stripLineToNChars( String str, int nbChars )
616 {
617 int strLength = str.length();
618
619 if ( strLength <= nbChars )
620 {
621 return str;
622 }
623
624 if ( nbChars < 2 )
625 {
626 throw new IllegalArgumentException( I18n.err( I18n.ERR_12084 ) );
627 }
628
629
630
631 int charsPerLine = nbChars - 1;
632
633 int remaining = ( strLength - nbChars ) % charsPerLine;
634
635 int nbLines = 1 + ( ( strLength - nbChars ) / charsPerLine ) + ( remaining == 0 ? 0 : 1 );
636
637 int nbCharsTotal = strLength + nbLines + nbLines - 2;
638
639 char[] buffer = new char[nbCharsTotal];
640 char[] orig = str.toCharArray();
641
642 int posSrc = 0;
643 int posDst = 0;
644
645 System.arraycopy( orig, posSrc, buffer, posDst, nbChars );
646 posSrc += nbChars;
647 posDst += nbChars;
648
649 for ( int i = 0; i < nbLines - 2; i++ )
650 {
651 buffer[posDst++] = '\n';
652 buffer[posDst++] = ' ';
653
654 System.arraycopy( orig, posSrc, buffer, posDst, charsPerLine );
655 posSrc += charsPerLine;
656 posDst += charsPerLine;
657 }
658
659 buffer[posDst++] = '\n';
660 buffer[posDst++] = ' ';
661 System.arraycopy( orig, posSrc, buffer, posDst, remaining == 0 ? charsPerLine : remaining );
662
663 return new String( buffer );
664 }
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684 public static Attributes createJndiAttributes( Object... avas ) throws LdapException
685 {
686 StringBuilder sb = new StringBuilder();
687 int pos = 0;
688 boolean valueExpected = false;
689
690 for ( Object ava : avas )
691 {
692 if ( !valueExpected )
693 {
694 if ( !( ava instanceof String ) )
695 {
696 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
697 I18n.ERR_12085, ( pos + 1 ) ) );
698 }
699
700 String attribute = ( String ) ava;
701 sb.append( attribute );
702
703 if ( attribute.indexOf( ':' ) != -1 )
704 {
705 sb.append( '\n' );
706 }
707 else
708 {
709 valueExpected = true;
710 }
711 }
712 else
713 {
714 if ( ava instanceof String )
715 {
716 sb.append( ": " ).append( ( String ) ava ).append( '\n' );
717 }
718 else if ( ava instanceof byte[] )
719 {
720 sb.append( ":: " );
721 sb.append( new String( Base64.encode( ( byte[] ) ava ) ) );
722 sb.append( '\n' );
723 }
724 else
725 {
726 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
727 I18n.ERR_12086, ( pos + 1 ) ) );
728 }
729
730 valueExpected = false;
731 }
732 }
733
734 if ( valueExpected )
735 {
736 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n
737 .err( I18n.ERR_12087 ) );
738 }
739
740 LdifAttributesReader reader = new LdifAttributesReader();
741 Attributes attributes = AttributeUtils.toAttributes( reader.parseEntry( sb.toString() ) );
742
743 try
744 {
745 reader.close();
746 }
747 catch ( IOException e )
748 {
749 e.printStackTrace();
750 }
751
752 return attributes;
753 }
754 }