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.entry;
21
22
23 import java.text.ParseException;
24 import java.util.Arrays;
25 import java.util.Iterator;
26
27 import javax.naming.NamingEnumeration;
28 import javax.naming.NamingException;
29 import javax.naming.directory.Attributes;
30 import javax.naming.directory.BasicAttribute;
31 import javax.naming.directory.BasicAttributes;
32
33 import org.apache.directory.api.i18n.I18n;
34 import org.apache.directory.api.ldap.model.exception.LdapException;
35 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeTypeException;
36 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
37 import org.apache.directory.api.ldap.model.name.Dn;
38 import org.apache.directory.api.util.Chars;
39 import org.apache.directory.api.util.Position;
40 import org.apache.directory.api.util.Strings;
41
42
43
44
45
46
47
48 public final class AttributeUtils
49 {
50 private AttributeUtils()
51 {
52 }
53
54
55
56
57
58
59
60
61
62
63
64 public static boolean containsValueCaseIgnore( javax.naming.directory.Attribute attr, Object value )
65 {
66
67 if ( attr.contains( value ) )
68 {
69 return true;
70 }
71
72 try
73 {
74 if ( value instanceof String )
75 {
76 String strVal = ( String ) value;
77
78 NamingEnumeration<?> attrVals = attr.getAll();
79
80 while ( attrVals.hasMoreElements() )
81 {
82 Object attrVal = attrVals.nextElement();
83
84 if ( attrVal instanceof String && strVal.equalsIgnoreCase( ( String ) attrVal ) )
85 {
86 return true;
87 }
88 }
89 }
90 else
91 {
92 byte[] valueBytes = ( byte[] ) value;
93
94 NamingEnumeration<?> attrVals = attr.getAll();
95
96 while ( attrVals.hasMoreElements() )
97 {
98 Object attrVal = attrVals.nextElement();
99
100 if ( attrVal instanceof byte[] && Arrays.equals( ( byte[] ) attrVal, valueBytes ) )
101 {
102 return true;
103 }
104 }
105 }
106 }
107 catch ( NamingException ne )
108 {
109 return false;
110 }
111
112 return false;
113 }
114
115
116
117
118
119
120
121
122
123
124 public static Attributes toCaseInsensitive( Attributes attributes )
125 {
126 if ( attributes == null )
127 {
128 return attributes;
129 }
130
131 if ( attributes instanceof BasicAttributes )
132 {
133 if ( attributes.isCaseIgnored() )
134 {
135
136 return attributes;
137 }
138 else
139 {
140
141
142 Attributes newAttrs = new BasicAttributes( true );
143
144 NamingEnumeration<?> attrs = attributes.getAll();
145
146 if ( attrs != null )
147 {
148
149 while ( attrs.hasMoreElements() )
150 {
151 newAttrs.put( ( javax.naming.directory.Attribute ) attrs.nextElement() );
152 }
153 }
154
155 return newAttrs;
156 }
157 }
158 else
159 {
160
161 return attributes;
162 }
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179 private static void parseOptions( char[] str, Position pos ) throws ParseException
180 {
181 while ( Strings.isCharASCII( str, pos.start, ';' ) )
182 {
183 pos.start++;
184
185
186 if ( !Chars.isAlphaDigitMinus( str, pos.start ) )
187 {
188
189 throw new ParseException( I18n.err( I18n.ERR_13201_EMPTY_OPTION_NOT_ALLOWED ), pos.start );
190 }
191
192 pos.start++;
193
194 while ( Chars.isAlphaDigitMinus( str, pos.start ) )
195 {
196 pos.start++;
197 }
198 }
199 }
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 private static void parseOptions( byte[] bytes, Position pos ) throws ParseException
218 {
219 while ( Strings.isCharASCII( bytes, pos.start, ';' ) )
220 {
221 pos.start++;
222
223
224 if ( !Chars.isAlphaDigitMinus( bytes, pos.start ) )
225 {
226
227 throw new ParseException( I18n.err( I18n.ERR_13201_EMPTY_OPTION_NOT_ALLOWED ), pos.start );
228 }
229
230 pos.start++;
231
232 while ( Chars.isAlphaDigitMinus( bytes, pos.start ) )
233 {
234 pos.start++;
235 }
236 }
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 private static boolean parseNumber( char[] filter, Position pos )
253 {
254 char c = Strings.charAt( filter, pos.start );
255
256 switch ( c )
257 {
258 case '0':
259
260 pos.start++;
261 return true;
262
263 case '1':
264 case '2':
265 case '3':
266 case '4':
267 case '5':
268 case '6':
269 case '7':
270 case '8':
271 case '9':
272 pos.start++;
273 break;
274
275 default:
276
277 return false;
278 }
279
280 while ( Chars.isDigit( filter, pos.start ) )
281 {
282 pos.start++;
283 }
284
285 return true;
286 }
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301 private static boolean parseNumber( byte[] bytes, Position pos )
302 {
303 byte b = Strings.byteAt( bytes, pos.start );
304
305 switch ( b )
306 {
307 case '0':
308
309 pos.start++;
310 return true;
311
312 case '1':
313 case '2':
314 case '3':
315 case '4':
316 case '5':
317 case '6':
318 case '7':
319 case '8':
320 case '9':
321 pos.start++;
322 break;
323
324 default:
325
326 return false;
327 }
328
329 while ( Chars.isDigit( bytes, pos.start ) )
330 {
331 pos.start++;
332 }
333
334 return true;
335 }
336
337
338
339
340
341
342
343
344
345
346
347
348 private static void parseOID( char[] str, Position pos ) throws ParseException
349 {
350
351 parseNumber( str, pos );
352
353
354 if ( !Strings.isCharASCII( str, pos.start, '.' ) )
355 {
356 throw new ParseException( I18n.err( I18n.ERR_13221_INVALID_OID_MISSING_DOT ), pos.start );
357 }
358
359 pos.start++;
360
361 if ( !parseNumber( str, pos ) )
362 {
363 throw new ParseException( I18n.err( I18n.ERR_13202_INVALID_OID_MISSING_NUMBER ), pos.start );
364 }
365
366 while ( true )
367 {
368
369 if ( !Strings.isCharASCII( str, pos.start, '.' ) )
370 {
371 break;
372 }
373
374 pos.start++;
375
376 if ( !parseNumber( str, pos ) )
377 {
378 throw new ParseException( I18n.err( I18n.ERR_13202_INVALID_OID_MISSING_NUMBER ), pos.start );
379 }
380 }
381 }
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396 private static void parseOID( byte[] bytes, Position pos ) throws ParseException
397 {
398
399 parseNumber( bytes, pos );
400
401
402 if ( !Strings.isCharASCII( bytes, pos.start, '.' ) )
403 {
404 throw new ParseException( I18n.err( I18n.ERR_13221_INVALID_OID_MISSING_DOT ), pos.start );
405 }
406
407 pos.start++;
408
409 if ( !parseNumber( bytes, pos ) )
410 {
411 throw new ParseException( I18n.err( I18n.ERR_13202_INVALID_OID_MISSING_NUMBER ), pos.start );
412 }
413
414 while ( true )
415 {
416
417 if ( !Strings.isCharASCII( bytes, pos.start, '.' ) )
418 {
419 break;
420 }
421
422 pos.start++;
423
424 if ( !parseNumber( bytes, pos ) )
425 {
426 throw new ParseException( I18n.err( I18n.ERR_13202_INVALID_OID_MISSING_NUMBER ), pos.start );
427 }
428 }
429 }
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453 public static String parseAttribute( char[] str, Position pos, boolean withOption, boolean relaxed )
454 throws ParseException
455 {
456
457 char c = Strings.charAt( str, pos.start );
458
459 if ( c == '\0' )
460 {
461 throw new ParseException( I18n.err( I18n.ERR_13222_EMPTY_ATTRIBUTE ), pos.start );
462 }
463
464 int start = pos.start;
465
466 if ( Chars.isAlpha( c ) )
467 {
468
469 pos.start++;
470
471 while ( Chars.isAlphaDigitMinus( str, pos.start ) || ( relaxed && Chars.isCharASCII( str, pos.start, '_' ) ) )
472 {
473 pos.start++;
474 }
475
476
477 if ( withOption )
478 {
479 parseOptions( str, pos );
480 }
481
482 return new String( str, start, pos.start - start );
483 }
484 else if ( Chars.isDigit( c ) )
485 {
486
487 pos.start++;
488
489
490 parseOID( str, pos );
491
492
493 if ( withOption )
494 {
495 parseOptions( str, pos );
496 }
497
498 return new String( str, start, pos.start - start );
499 }
500 else
501 {
502 throw new ParseException( I18n.err( I18n.ERR_13223_BAD_CHAR_IN_ATTRIBUTE ), pos.start );
503 }
504 }
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530 public static String parseAttribute( byte[] bytes, Position pos, boolean withOption, boolean relaxed )
531 throws ParseException
532 {
533
534 byte b = Strings.byteAt( bytes, pos.start );
535
536 if ( b == '\0' )
537 {
538 throw new ParseException( I18n.err( I18n.ERR_13222_EMPTY_ATTRIBUTE ), pos.start );
539 }
540
541 int start = pos.start;
542
543 if ( Chars.isAlpha( b ) )
544 {
545
546 while ( Chars.isAlphaDigitMinus( bytes, pos.start ) || ( relaxed && Strings.isCharASCII( bytes, pos.start, '_' ) ) )
547 {
548 pos.start++;
549 }
550
551
552 if ( withOption )
553 {
554 parseOptions( bytes, pos );
555 }
556
557 return Strings.utf8ToString( bytes, start, pos.start - start );
558 }
559 else if ( Chars.isDigit( b ) )
560 {
561
562 parseOID( bytes, pos );
563
564
565 if ( withOption )
566 {
567 parseOptions( bytes, pos );
568 }
569
570 return Strings.utf8ToString( bytes, start, pos.start - start );
571 }
572 else
573 {
574 throw new ParseException( I18n.err( I18n.ERR_13223_BAD_CHAR_IN_ATTRIBUTE ), pos.start );
575 }
576 }
577
578
579
580
581
582
583
584
585
586 public static void applyModification( Entry entry, Modification modification ) throws LdapException
587 {
588 Attribute modAttr = modification.getAttribute();
589 String modificationId = modAttr.getUpId();
590
591 switch ( modification.getOperation() )
592 {
593 case ADD_ATTRIBUTE:
594 Attribute modifiedAttr = entry.get( modificationId );
595
596 if ( modifiedAttr == null )
597 {
598
599 entry.put( modAttr );
600 }
601 else
602 {
603
604
605 for ( Value value : modAttr )
606 {
607
608
609
610 modifiedAttr.add( value );
611 }
612 }
613
614 break;
615
616 case REMOVE_ATTRIBUTE:
617 if ( modAttr.get() == null )
618 {
619
620
621
622 entry.removeAttributes( modificationId );
623 }
624 else
625 {
626
627
628 modifiedAttr = entry.get( modificationId );
629
630 if ( modifiedAttr == null )
631 {
632 break;
633 }
634
635 for ( Value value : modAttr )
636 {
637
638
639
640 modifiedAttr.remove( value );
641 }
642
643 if ( modifiedAttr.size() == 0 )
644 {
645
646 entry.removeAttributes( modifiedAttr.getUpId() );
647 }
648 }
649
650 break;
651
652 case REPLACE_ATTRIBUTE:
653 if ( modAttr.get() == null )
654 {
655
656
657 entry.removeAttributes( modificationId );
658 }
659 else
660 {
661
662 entry.put( modAttr );
663 }
664
665 break;
666 default:
667 break;
668 }
669 }
670
671
672
673
674
675
676
677
678
679
680
681 public static Entry toEntry( Attributes attributes, Dn dn ) throws LdapException
682 {
683 if ( attributes instanceof BasicAttributes )
684 {
685 try
686 {
687 Entry entry = new DefaultEntry( dn );
688
689 for ( NamingEnumeration<? extends javax.naming.directory.Attribute> attrs = attributes.getAll(); attrs
690 .hasMoreElements(); )
691 {
692 javax.naming.directory.Attribute attr = attrs.nextElement();
693
694 Attribute entryAttribute = toApiAttribute( attr );
695
696 if ( entryAttribute != null )
697 {
698 entry.put( entryAttribute );
699 }
700 }
701
702 return entry;
703 }
704 catch ( LdapException ne )
705 {
706 throw new LdapInvalidAttributeTypeException( ne.getMessage(), ne );
707 }
708 }
709 else
710 {
711 return null;
712 }
713 }
714
715
716
717
718
719
720
721
722
723
724 public static Attributes toAttributes( Entry entry )
725 {
726 if ( entry != null )
727 {
728 Attributes attributes = new BasicAttributes( true );
729
730
731 for ( Iterator<Attribute> attributeIterator = entry.iterator(); attributeIterator.hasNext(); )
732 {
733 Attribute entryAttribute = attributeIterator.next();
734
735 attributes.put( toJndiAttribute( entryAttribute ) );
736 }
737
738 return attributes;
739 }
740
741 return null;
742 }
743
744
745
746
747
748
749
750
751 public static javax.naming.directory.Attribute toJndiAttribute( Attribute attribute )
752 {
753 if ( attribute != null )
754 {
755 javax.naming.directory.Attribute jndiAttribute = new BasicAttribute( attribute.getUpId() );
756
757
758 for ( Iterator<Value> valueIterator = attribute.iterator(); valueIterator.hasNext(); )
759 {
760 Value value = valueIterator.next();
761
762 if ( value.isHumanReadable() )
763 {
764 jndiAttribute.add( value.getString() );
765 }
766 else
767 {
768 jndiAttribute.add( value.getBytes() );
769 }
770 }
771
772 return jndiAttribute;
773 }
774
775 return null;
776 }
777
778
779
780
781
782
783
784
785
786 public static Attribute toApiAttribute( javax.naming.directory.Attribute jndiAttribute )
787 throws LdapInvalidAttributeValueException
788 {
789 if ( jndiAttribute == null )
790 {
791 return null;
792 }
793
794 try
795 {
796 Attribute attribute = new DefaultAttribute( jndiAttribute.getID() );
797
798 for ( NamingEnumeration<?> values = jndiAttribute.getAll(); values.hasMoreElements(); )
799 {
800 Object value = values.nextElement();
801
802 if ( value instanceof String )
803 {
804 attribute.add( ( String ) value );
805 }
806 else if ( value instanceof byte[] )
807 {
808 attribute.add( ( byte[] ) value );
809 }
810 else
811 {
812 attribute.add( ( String ) null );
813 }
814 }
815
816 return attribute;
817 }
818 catch ( NamingException ne )
819 {
820 return null;
821 }
822 }
823 }