1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.directory.api.ldap.model.name;
22
23
24 import java.io.Externalizable;
25 import java.io.IOException;
26 import java.io.ObjectInput;
27 import java.io.ObjectOutput;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.TreeSet;
36
37 import org.apache.commons.collections.list.UnmodifiableList;
38 import org.apache.directory.api.i18n.I18n;
39 import org.apache.directory.api.ldap.model.entry.BinaryValue;
40 import org.apache.directory.api.ldap.model.entry.StringValue;
41 import org.apache.directory.api.ldap.model.entry.Value;
42 import org.apache.directory.api.ldap.model.exception.LdapException;
43 import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
44 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
45 import org.apache.directory.api.ldap.model.schema.AttributeType;
46 import org.apache.directory.api.ldap.model.schema.SchemaManager;
47 import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
48 import org.apache.directory.api.util.Strings;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public class Dn implements Iterable<Rdn>, Externalizable
74 {
75
76 protected static final Logger LOG = LoggerFactory.getLogger( Dn.class );
77
78
79
80
81
82
83
84
85 private static final long serialVersionUID = 1L;
86
87
88 public static final int NOT_EQUAL = -1;
89
90
91 public static final int EQUAL = 0;
92
93
94
95
96
97
98
99
100
101
102
103
104
105 protected List<Rdn> rdns = new ArrayList<>( 5 );
106
107
108 private String upName;
109
110
111 private String normName;
112
113
114 private byte[] bytes;
115
116
117 public static final Dn EMPTY_DN = new Dn();
118
119
120 public static final Dn ROOT_DSE = new Dn();
121
122
123 private SchemaManager schemaManager;
124
125
126
127
128 private final class RdnIterator implements Iterator<Rdn>
129 {
130
131 int index;
132
133
134 private RdnIterator()
135 {
136 index = rdns != null ? rdns.size() - 1 : -1;
137 }
138
139
140
141
142
143 @Override
144 public boolean hasNext()
145 {
146 return index >= 0;
147 }
148
149
150
151
152
153 @Override
154 public Rdn next()
155 {
156 return index >= 0 ? rdns.get( index-- ) : null;
157 }
158
159
160
161
162
163 @Override
164 public void remove()
165 {
166
167 }
168 }
169
170
171
172
173
174 public Dn()
175 {
176 this( ( SchemaManager ) null );
177 }
178
179
180
181
182
183
184
185 public Dn( SchemaManager schemaManager )
186 {
187 this.schemaManager = schemaManager;
188 upName = "";
189 normName = "";
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 public Dn( String... upRdns ) throws LdapInvalidDnException
216 {
217 this( null, upRdns );
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244 public Dn( SchemaManager schemaManager, String... upRdns ) throws LdapInvalidDnException
245 {
246 StringBuilder sb = new StringBuilder();
247 boolean valueExpected = false;
248 boolean isFirst = true;
249
250 for ( String upRdn : upRdns )
251 {
252 if ( Strings.isEmpty( upRdn ) )
253 {
254 continue;
255 }
256
257 if ( isFirst )
258 {
259 isFirst = false;
260 }
261 else if ( !valueExpected )
262 {
263 sb.append( ',' );
264 }
265
266 if ( !valueExpected )
267 {
268 sb.append( upRdn );
269
270 if ( upRdn.indexOf( '=' ) == -1 )
271 {
272 valueExpected = true;
273 }
274 }
275 else
276 {
277 sb.append( "=" ).append( upRdn );
278
279 valueExpected = false;
280 }
281 }
282
283 if ( !isFirst && valueExpected )
284 {
285 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04202 ) );
286 }
287
288
289
290 upName = sb.toString();
291
292 try
293 {
294 parseInternal( upName, rdns );
295 apply( schemaManager );
296 }
297 catch ( LdapInvalidDnException e )
298 {
299 if ( schemaManager == null || !schemaManager.isRelaxed() )
300 {
301 throw e;
302 }
303
304
305
306
307 }
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321 Dn( SchemaManager schemaManager, String upName, String normName, Rdn... rdns )
322 {
323 this.schemaManager = schemaManager;
324 this.upName = upName;
325 this.normName = normName;
326 bytes = Strings.getBytesUtf8Ascii( upName );
327 this.rdns = Arrays.asList( rdns );
328 }
329
330
331
332
333
334
335
336
337 public Dn( Rdn... rdns ) throws LdapInvalidDnException
338 {
339 if ( rdns == null )
340 {
341 return;
342 }
343
344 for ( Rdn rdn : rdns )
345 {
346 this.rdns.add( rdn );
347 }
348
349 apply( null );
350 toUpName();
351 }
352
353
354
355
356
357
358
359
360
361 public Dn( Rdn rdn, Dn dn ) throws LdapInvalidDnException
362 {
363 if ( ( dn == null ) || ( rdn == null ) )
364 {
365 throw new IllegalArgumentException( "Either the dn or the rdn is null" );
366 }
367
368 for ( Rdn rdnParent : dn )
369 {
370 rdns.add( 0, rdnParent );
371 }
372
373 rdns.add( 0, rdn );
374
375 apply( dn.schemaManager );
376 toUpName();
377 }
378
379
380
381
382
383
384
385
386
387 public Dn( SchemaManager schemaManager, Rdn... rdns ) throws LdapInvalidDnException
388 {
389 if ( rdns == null )
390 {
391 return;
392 }
393
394 for ( Rdn rdn : rdns )
395 {
396 this.rdns.add( rdn );
397 }
398
399 apply( schemaManager );
400 toUpName();
401 }
402
403
404
405
406
407
408
409 public SchemaManager getSchemaManager()
410 {
411 return schemaManager;
412 }
413
414
415
416
417
418
419
420 private String toUpName()
421 {
422 if ( rdns.isEmpty() )
423 {
424 upName = "";
425 }
426 else
427 {
428 StringBuilder sb = new StringBuilder();
429 boolean isFirst = true;
430
431 for ( Rdn rdn : rdns )
432 {
433 if ( isFirst )
434 {
435 isFirst = false;
436 }
437 else
438 {
439 sb.append( ',' );
440 }
441
442 sb.append( rdn.getName() );
443 }
444
445 upName = sb.toString();
446 }
447
448 return upName;
449 }
450
451
452
453
454
455
456
457
458 @Override
459 public int hashCode()
460 {
461 int result = 37;
462
463 for ( Rdn rdn : rdns )
464 {
465 result = result * 17 + rdn.hashCode();
466 }
467
468 return result;
469 }
470
471
472
473
474
475
476
477 public String getName()
478 {
479 return upName == null ? "" : upName;
480 }
481
482
483
484
485
486
487
488
489
490 void setUpName( String upName )
491 {
492 this.upName = upName;
493 }
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512 public String getNormName()
513 {
514 return normName;
515 }
516
517
518
519
520
521
522 public int size()
523 {
524 return rdns.size();
525 }
526
527
528
529
530
531
532
533
534 public static int getNbBytes( Dn dn )
535 {
536 return dn.bytes == null ? 0 : dn.bytes.length;
537 }
538
539
540
541
542
543
544
545
546 public static byte[] getBytes( Dn dn )
547 {
548 return dn == null ? null : dn.bytes;
549 }
550
551
552
553
554
555
556
557
558
559
560 public boolean isAncestorOf( String dn )
561 {
562 try
563 {
564 return isAncestorOf( new Dn( dn ) );
565 }
566 catch ( LdapInvalidDnException lide )
567 {
568 return false;
569 }
570 }
571
572
573
574
575
576
577
578
579
580
581 public boolean isAncestorOf( Dn dn )
582 {
583 if ( dn == null )
584 {
585 return false;
586 }
587
588 return dn.isDescendantOf( this );
589 }
590
591
592
593
594
595
596
597
598
599
600 public boolean isDescendantOf( String dn )
601 {
602 try
603 {
604 return isDescendantOf( new Dn( schemaManager, dn ) );
605 }
606 catch ( LdapInvalidDnException lide )
607 {
608 return false;
609 }
610 }
611
612
613
614
615
616
617
618
619
620
621 public boolean isDescendantOf( Dn dn )
622 {
623 if ( ( dn == null ) || dn.isRootDse() )
624 {
625 return true;
626 }
627
628 if ( dn.size() > size() )
629 {
630
631 return false;
632 }
633
634
635
636
637 for ( int i = dn.size() - 1; i >= 0; i-- )
638 {
639 Rdn nameRdn = dn.rdns.get( dn.rdns.size() - i - 1 );
640 Rdn ldapRdn = rdns.get( rdns.size() - i - 1 );
641
642 if ( !nameRdn.equals( ldapRdn ) )
643 {
644 return false;
645 }
646 }
647
648 return true;
649 }
650
651
652
653
654
655
656
657 public boolean isEmpty()
658 {
659 return rdns.isEmpty();
660 }
661
662
663
664
665
666
667
668 public boolean isRootDse()
669 {
670 return rdns.isEmpty();
671 }
672
673
674
675
676
677
678
679
680
681
682
683 public Rdn getRdn( int posn )
684 {
685 if ( rdns.isEmpty() )
686 {
687 return null;
688 }
689
690 if ( ( posn < 0 ) || ( posn >= rdns.size() ) )
691 {
692 throw new IllegalArgumentException( "Invalid position : " + posn );
693 }
694
695 return rdns.get( posn );
696 }
697
698
699
700
701
702
703
704 public Rdn getRdn()
705 {
706 if ( isNullOrEmpty( this ) )
707 {
708 return Rdn.EMPTY_RDN;
709 }
710
711 return rdns.get( 0 );
712 }
713
714
715
716
717
718
719
720 @SuppressWarnings("unchecked")
721 public List<Rdn> getRdns()
722 {
723 return UnmodifiableList.decorate( rdns );
724 }
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745 public Dn getDescendantOf( String ancestor ) throws LdapInvalidDnException
746 {
747 return getDescendantOf( new Dn( schemaManager, ancestor ) );
748 }
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768 public Dn getDescendantOf( Dn ancestor ) throws LdapInvalidDnException
769 {
770 if ( ( ancestor == null ) || ( ancestor.size() == 0 ) )
771 {
772 return this;
773 }
774
775 if ( rdns.isEmpty() )
776 {
777 return EMPTY_DN;
778 }
779
780 int length = ancestor.size();
781
782 if ( length > rdns.size() )
783 {
784 String message = I18n.err( I18n.ERR_04206, length, rdns.size() );
785 LOG.error( message );
786 throw new ArrayIndexOutOfBoundsException( message );
787 }
788
789 Dn newDn = new Dn( schemaManager );
790 List<Rdn> rdnsAncestor = ancestor.getRdns();
791
792 for ( int i = 0; i < ancestor.size(); i++ )
793 {
794 Rdn rdn = rdns.get( size() - 1 - i );
795 Rdn rdnDescendant = rdnsAncestor.get( ancestor.size() - 1 - i );
796
797 if ( !rdn.equals( rdnDescendant ) )
798 {
799 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX );
800 }
801 }
802
803 for ( int i = 0; i < rdns.size() - length; i++ )
804 {
805 newDn.rdns.add( rdns.get( i ) );
806 }
807
808 newDn.toUpName();
809 newDn.apply( schemaManager, true );
810
811 return newDn;
812 }
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833 public Dn getAncestorOf( String descendant ) throws LdapInvalidDnException
834 {
835 return getAncestorOf( new Dn( schemaManager, descendant ) );
836 }
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857 public Dn getAncestorOf( Dn descendant ) throws LdapInvalidDnException
858 {
859 if ( ( descendant == null ) || ( descendant.size() == 0 ) )
860 {
861 return this;
862 }
863
864 if ( rdns.isEmpty() )
865 {
866 return EMPTY_DN;
867 }
868
869 int length = descendant.size();
870
871 if ( length > rdns.size() )
872 {
873 String message = I18n.err( I18n.ERR_04206, length, rdns.size() );
874 LOG.error( message );
875 throw new ArrayIndexOutOfBoundsException( message );
876 }
877
878 Dn newDn = new Dn( schemaManager );
879 List<Rdn> rdnsDescendant = descendant.getRdns();
880
881 for ( int i = 0; i < descendant.size(); i++ )
882 {
883 Rdn rdn = rdns.get( i );
884 Rdn rdnDescendant = rdnsDescendant.get( i );
885
886 if ( !rdn.equals( rdnDescendant ) )
887 {
888 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX );
889 }
890 }
891
892 for ( int i = length; i < rdns.size(); i++ )
893 {
894 newDn.rdns.add( rdns.get( i ) );
895 }
896
897 newDn.toUpName();
898 newDn.apply( schemaManager, true );
899
900 return newDn;
901 }
902
903
904
905
906
907
908
909
910
911
912
913 public Dn add( Dn suffix ) throws LdapInvalidDnException
914 {
915 if ( ( suffix == null ) || ( suffix.size() == 0 ) )
916 {
917 return this;
918 }
919
920 Dn clonedDn = copy();
921
922
923 clonedDn.rdns.addAll( 0, suffix.rdns );
924
925
926 if ( clonedDn.isSchemaAware() && suffix.isSchemaAware() )
927 {
928 if ( clonedDn.size() != 0 )
929 {
930 clonedDn.normName = suffix.getNormName() + "," + normName;
931 clonedDn.bytes = Strings.getBytesUtf8Ascii( normName );
932 clonedDn.upName = suffix.getName() + "," + upName;
933 }
934 }
935 else
936 {
937 clonedDn.apply( schemaManager, true );
938 clonedDn.toUpName();
939 }
940
941 return clonedDn;
942 }
943
944
945
946
947
948
949
950
951
952
953
954 public Dn add( String comp ) throws LdapInvalidDnException
955 {
956 if ( comp.length() == 0 )
957 {
958 return this;
959 }
960
961 Dn clonedDn = copy();
962
963
964 Rdn newRdn = new Rdn( schemaManager, comp );
965
966 clonedDn.rdns.add( 0, newRdn );
967
968 clonedDn.apply( schemaManager, true );
969 clonedDn.toUpName();
970
971 return clonedDn;
972 }
973
974
975
976
977
978
979
980
981
982 public Dn add( Rdn newRdn ) throws LdapInvalidDnException
983 {
984 if ( ( newRdn == null ) || ( newRdn.size() == 0 ) )
985 {
986 return this;
987 }
988
989 Dn clonedDn = copy();
990
991 clonedDn.rdns.add( 0, newRdn );
992 clonedDn.apply( schemaManager, true );
993 clonedDn.toUpName();
994
995 return clonedDn;
996 }
997
998
999
1000
1001
1002
1003
1004
1005
1006 public Dn getParent()
1007 {
1008 if ( isNullOrEmpty( this ) )
1009 {
1010 return this;
1011 }
1012
1013 int posn = rdns.size() - 1;
1014
1015 Dn newDn = new Dn( schemaManager );
1016
1017 for ( int i = rdns.size() - posn; i < rdns.size(); i++ )
1018 {
1019 newDn.rdns.add( rdns.get( i ) );
1020 }
1021
1022 try
1023 {
1024 newDn.apply( schemaManager, true );
1025 }
1026 catch ( LdapInvalidDnException e )
1027 {
1028 LOG.error( e.getMessage(), e );
1029 }
1030
1031 newDn.toUpName();
1032
1033 return newDn;
1034 }
1035
1036
1037
1038
1039
1040 private Dn copy()
1041 {
1042 Dn dn = new Dn( schemaManager );
1043 dn.rdns = new ArrayList<>();
1044
1045 for ( Rdn rdn : rdns )
1046 {
1047 dn.rdns.add( rdn );
1048 }
1049
1050 return dn;
1051 }
1052
1053
1054
1055
1056
1057
1058 @Override
1059 public boolean equals( Object obj )
1060 {
1061 if ( obj instanceof String )
1062 {
1063 return normName.equals( obj );
1064 }
1065 else if ( obj instanceof Dn )
1066 {
1067 Dn name = ( Dn ) obj;
1068
1069 if ( name.getNormName().equals( normName ) )
1070 {
1071 return true;
1072 }
1073
1074 if ( name.size() != this.size() )
1075 {
1076 return false;
1077 }
1078
1079 for ( int i = 0; i < this.size(); i++ )
1080 {
1081 if ( !name.rdns.get( i ).equals( rdns.get( i ) ) )
1082 {
1083 return false;
1084 }
1085 }
1086
1087
1088 return true;
1089 }
1090 else
1091 {
1092 return false;
1093 }
1094 }
1095
1096
1097
1098
1099
1100 private static Ava atavOidToName( Ava atav, SchemaManager schemaManager )
1101 throws LdapInvalidDnException
1102 {
1103 Map<String, OidNormalizer> oidsMap = schemaManager.getNormalizerMapping();
1104 String type = Strings.trim( atav.getNormType() );
1105
1106 if ( ( type.startsWith( "oid." ) ) || ( type.startsWith( "OID." ) ) )
1107 {
1108 type = type.substring( 4 );
1109 }
1110
1111 if ( Strings.isNotEmpty( type ) )
1112 {
1113 if ( oidsMap == null )
1114 {
1115 return atav;
1116 }
1117
1118 type = Strings.toLowerCaseAscii( type );
1119
1120
1121 if ( !oidsMap.containsKey( type ) )
1122 {
1123
1124 String msg = I18n.err( I18n.ERR_04268_OID_NOT_FOUND, atav.getType() );
1125 LOG.error( msg );
1126 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, msg );
1127 }
1128
1129 OidNormalizer oidNormalizer = oidsMap.get( type );
1130
1131 if ( oidNormalizer != null )
1132 {
1133 try
1134 {
1135 AttributeType attributeType = schemaManager.getAttributeType( type );
1136 if ( attributeType == null )
1137 {
1138
1139
1140
1141
1142 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX,
1143 I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED, type ) );
1144 }
1145 Value<?> atavValue;
1146 Value<?> value = atav.getValue();
1147
1148 if ( value instanceof StringValue )
1149 {
1150
1151
1152
1153 if ( attributeType.getSyntax() == null || attributeType.getSyntax().isHumanReadable() )
1154 {
1155 atavValue = new StringValue( attributeType, value.getString() );
1156 }
1157 else
1158 {
1159
1160 atavValue = new BinaryValue( attributeType, value.getBytes() );
1161 }
1162 }
1163 else
1164 {
1165 atavValue = new BinaryValue( attributeType, atav.getValue().getBytes() );
1166 }
1167
1168 return new Ava(
1169 attributeType,
1170 atav.getType(),
1171 oidNormalizer.getAttributeTypeOid(),
1172 atavValue,
1173 atav.getName() );
1174 }
1175 catch ( LdapException le )
1176 {
1177 throw new LdapInvalidDnException( le.getMessage(), le );
1178 }
1179 }
1180 else
1181 {
1182
1183 return atav;
1184 }
1185 }
1186 else
1187 {
1188
1189 String msg = I18n.err( I18n.ERR_04209_EMPTY_TYPE_NOT_ALLOWED );
1190 LOG.error( msg );
1191 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, msg );
1192 }
1193 }
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205 static void rdnOidToName( Rdn rdn, SchemaManager schemaManager ) throws LdapInvalidDnException
1206 {
1207
1208
1209 if ( rdn.size() < 2 )
1210 {
1211 Ava newAtav = atavOidToName( rdn.getAva(), schemaManager );
1212 rdn.replaceAva( newAtav, 0 );
1213 }
1214 else
1215 {
1216 Set<String> sortedOids = new TreeSet<>();
1217 Map<String, Ava> avas = new HashMap<>();
1218
1219
1220 for ( Ava val : rdn )
1221 {
1222 Ava newAtav = atavOidToName( val, schemaManager );
1223 String oid = newAtav.getAttributeType().getOid();
1224 sortedOids.add( oid );
1225 avas.put( oid, newAtav );
1226 }
1227
1228
1229 int pos = 0;
1230
1231 for ( String oid : sortedOids )
1232 {
1233 rdn.replaceAva( avas.get( oid ), pos++ );
1234 }
1235 }
1236 }
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248 public Dn apply( SchemaManager schemaManager, boolean force ) throws LdapInvalidDnException
1249 {
1250 if ( ( this.schemaManager == null ) || force )
1251 {
1252 this.schemaManager = schemaManager;
1253
1254 if ( this.schemaManager != null )
1255 {
1256 synchronized ( this )
1257 {
1258 if ( size() == 0 )
1259 {
1260 bytes = null;
1261 normName = "";
1262
1263 return this;
1264 }
1265
1266 StringBuilder sb = new StringBuilder();
1267 boolean isFirst = true;
1268
1269 for ( Rdn rdn : rdns )
1270 {
1271 rdn.apply( schemaManager );
1272
1273 if ( isFirst )
1274 {
1275 isFirst = false;
1276 }
1277 else
1278 {
1279 sb.append( ',' );
1280 }
1281
1282 sb.append( rdn.getNormName() );
1283 }
1284
1285 String newNormName = sb.toString();
1286
1287 if ( ( normName == null ) || !normName.equals( newNormName ) )
1288 {
1289 bytes = Strings.getBytesUtf8Ascii( newNormName );
1290 normName = newNormName;
1291 }
1292 }
1293 }
1294 else
1295 {
1296 if ( rdns.isEmpty() )
1297 {
1298 bytes = null;
1299 normName = "";
1300 }
1301 else
1302 {
1303 StringBuilder sb = new StringBuilder();
1304 boolean isFirst = true;
1305
1306 for ( Rdn rdn : rdns )
1307 {
1308 if ( isFirst )
1309 {
1310 isFirst = false;
1311 }
1312 else
1313 {
1314 sb.append( ',' );
1315 }
1316
1317 sb.append( rdn.getNormName() );
1318 }
1319
1320 String newNormName = sb.toString();
1321
1322 if ( ( normName == null ) || !normName.equals( newNormName ) )
1323 {
1324 bytes = Strings.getBytesUtf8Ascii( newNormName );
1325 normName = newNormName;
1326 }
1327 }
1328 }
1329 }
1330
1331 return this;
1332 }
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342 public Dn apply( SchemaManager schemaManager ) throws LdapInvalidDnException
1343 {
1344 if ( this.schemaManager != null )
1345 {
1346 return this;
1347 }
1348 else
1349 {
1350 return apply( schemaManager, true );
1351 }
1352 }
1353
1354
1355
1356
1357
1358
1359
1360 public boolean isSchemaAware()
1361 {
1362 return schemaManager != null;
1363 }
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385 @Override
1386 public Iterator<Rdn> iterator()
1387 {
1388 return new RdnIterator();
1389 }
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399 public static boolean isNullOrEmpty( Dn dn )
1400 {
1401 return ( dn == null ) || dn.isEmpty();
1402 }
1403
1404
1405
1406
1407
1408
1409
1410
1411 public static boolean isValid( String name )
1412 {
1413 Dn dn = new Dn();
1414
1415 try
1416 {
1417 parseInternal( name, dn.rdns );
1418 return true;
1419 }
1420 catch ( LdapInvalidDnException e )
1421 {
1422 return false;
1423 }
1424 }
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434 private static void parseInternal( String name, List<Rdn> rdns ) throws LdapInvalidDnException
1435 {
1436 try
1437 {
1438 FastDnParser.parseDn( name, rdns );
1439 }
1440 catch ( TooComplexDnException e )
1441 {
1442 rdns.clear();
1443 new ComplexDnParser().parseDn( name, rdns );
1444 }
1445 }
1446
1447
1448
1449
1450
1451 @Override
1452 public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
1453 {
1454
1455 upName = in.readUTF();
1456
1457
1458 normName = in.readUTF();
1459
1460 if ( normName.length() == 0 )
1461 {
1462
1463
1464
1465 normName = upName;
1466 }
1467
1468 bytes = Strings.getBytesUtf8Ascii( normName );
1469
1470
1471 int nbRdns = in.readInt();
1472
1473 rdns = new ArrayList<>( nbRdns );
1474
1475 for ( int i = 0; i < nbRdns; i++ )
1476 {
1477 Rdn rdn = new Rdn( schemaManager );
1478 rdn.readExternal( in );
1479 rdns.add( rdn );
1480 }
1481 }
1482
1483
1484
1485
1486
1487 @Override
1488 public void writeExternal( ObjectOutput out ) throws IOException
1489 {
1490 if ( upName == null )
1491 {
1492 String message = "Cannot serialize a NULL Dn";
1493 LOG.error( message );
1494 throw new IOException( message );
1495 }
1496
1497
1498 out.writeUTF( upName );
1499
1500
1501 if ( upName.equals( normName ) )
1502 {
1503 out.writeUTF( "" );
1504 }
1505 else
1506 {
1507 out.writeUTF( normName );
1508 }
1509
1510
1511
1512 out.writeInt( size() );
1513
1514
1515 for ( Rdn rdn : rdns )
1516 {
1517 rdn.writeExternal( out );
1518 }
1519
1520 out.flush();
1521 }
1522
1523
1524
1525
1526
1527
1528
1529
1530 @Override
1531 public String toString()
1532 {
1533 return getName();
1534 }
1535 }