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.name;
21
22
23 import java.io.Externalizable;
24 import java.io.IOException;
25 import java.io.ObjectInput;
26 import java.io.ObjectOutput;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32
33 import org.apache.directory.api.i18n.I18n;
34 import org.apache.directory.api.ldap.model.entry.Value;
35 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
36 import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
37 import org.apache.directory.api.ldap.model.schema.AttributeType;
38 import org.apache.directory.api.ldap.model.schema.SchemaManager;
39 import org.apache.directory.api.util.Chars;
40 import org.apache.directory.api.util.Hex;
41 import org.apache.directory.api.util.Serialize;
42 import org.apache.directory.api.util.Strings;
43 import org.apache.directory.api.util.Unicode;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public class Rdn implements Cloneable, Externalizable, Iterable<Ava>, Comparable<Rdn>
115 {
116
117 protected static final Logger LOG = LoggerFactory.getLogger( Rdn.class );
118
119
120 public static final Rdn EMPTY_RDN = new Rdn();
121
122
123
124
125
126
127
128
129 private static final long serialVersionUID = 1L;
130
131
132 String upName = null;
133
134
135 String normName;
136
137
138
139
140
141
142
143 transient List<Ava> avas = null;
144
145
146
147
148
149 transient Map<String, List<Ava>> avaTypes;
150
151
152
153
154 String avaType = null;
155
156
157
158
159
160
161 Ava ava = null;
162
163
164
165
166
167 int nbAvas = 0;
168
169
170 public static final int UNDEFINED = Integer.MAX_VALUE;
171
172
173 public static final int SUPERIOR = 1;
174
175
176 public static final int INFERIOR = -1;
177
178
179 public static final int EQUAL = 0;
180
181
182 private boolean normalized = false;
183
184
185 private transient SchemaManager schemaManager;
186
187
188 private volatile int h;
189
190
191
192
193
194 public Rdn()
195 {
196 this( ( SchemaManager ) null );
197 }
198
199
200
201
202
203
204
205
206 public Rdn( SchemaManager schemaManager )
207 {
208
209
210
211 this.schemaManager = schemaManager;
212 upName = "";
213 normName = "";
214 normalized = schemaManager != null;
215 h = 0;
216 }
217
218
219
220
221
222
223
224
225
226 public Rdn( SchemaManager schemaManager, String rdn ) throws LdapInvalidDnException
227 {
228 this.schemaManager = schemaManager;
229
230 if ( Strings.isNotEmpty( rdn ) )
231 {
232
233 parse( schemaManager, rdn, this );
234
235 if ( upName.length() < rdn.length() )
236 {
237 throw new LdapInvalidDnException( I18n.err( I18n.ERR_13625_INVALID_RDN ) );
238 }
239
240 upName = rdn;
241 }
242 else
243 {
244 upName = "";
245 normName = "";
246 normalized = true;
247 }
248
249 hashCode();
250 }
251
252
253
254
255
256
257
258
259 public Rdn( String rdn ) throws LdapInvalidDnException
260 {
261 this( ( SchemaManager ) null, rdn );
262 }
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 public Rdn( SchemaManager schemaManager, String upType, String upValue ) throws LdapInvalidDnException, LdapInvalidAttributeValueException
279 {
280 if ( schemaManager != null )
281 {
282 AttributeType attributeType = schemaManager.getAttributeType( upType );
283 addAVA( schemaManager, upType, new Value( attributeType, upValue ) );
284 }
285 else
286 {
287 addAVA( schemaManager, upType, new Value( upValue ) );
288 }
289
290 StringBuilder sb = new StringBuilder();
291 sb.append( upType ).append( '=' ).append( upValue );
292 upName = sb.toString();
293
294 sb.setLength( 0 );
295 sb.append( ava.getNormType() ).append( '=' );
296
297 Value value = ava.getValue();
298
299 if ( value != null )
300 {
301 sb.append( value.getNormalized() );
302 }
303
304 normName = sb.toString();
305 normalized = true;
306
307 hashCode();
308 }
309
310
311
312
313
314
315
316
317
318
319
320 public Rdn( String upType, String upValue ) throws LdapInvalidDnException, LdapInvalidAttributeValueException
321 {
322 this( null, upType, upValue );
323 }
324
325
326
327
328
329
330
331
332
333 public Rdn( SchemaManager schemaManager, Ava... avas ) throws LdapInvalidDnException
334 {
335 StringBuilder buffer = new StringBuilder();
336
337 for ( int i = 0; i < avas.length; i++ )
338 {
339 if ( i > 0 )
340 {
341 buffer.append( '+' );
342 }
343
344 addAVA( schemaManager, avas[i] );
345 buffer.append( avas[i].getName() );
346 }
347
348 setUpName( buffer.toString() );
349 hashCode();
350 }
351
352
353
354
355
356
357
358
359 public Rdn( Ava... avas ) throws LdapInvalidDnException
360 {
361 this( null, avas );
362 }
363
364
365
366
367
368
369
370
371 public Rdn( Rdn rdn )
372 {
373 nbAvas = rdn.size();
374 upName = rdn.getName();
375 normName = rdn.getName();
376 normalized = rdn.normalized;
377 schemaManager = rdn.schemaManager;
378
379 switch ( rdn.size() )
380 {
381 case 0:
382 hashCode();
383
384 return;
385
386 case 1:
387 this.ava = rdn.ava.clone();
388 hashCode();
389
390 return;
391
392 default:
393
394 avas = new ArrayList<>();
395 avaTypes = new HashMap<>();
396
397 for ( Ava currentAva : rdn.avas )
398 {
399 avas.add( currentAva );
400
401 List<Ava> avaList = avaTypes.get( currentAva.getNormType() );
402
403 if ( avaList == null )
404 {
405 avaList = new ArrayList<>();
406 avaList.add( currentAva );
407 avaTypes.put( currentAva.getNormType(), avaList );
408 avas.add( currentAva );
409 }
410 else
411 {
412 if ( !avaList.contains( currentAva ) )
413 {
414 avaList.add( currentAva );
415 avas.add( currentAva );
416 }
417 }
418 }
419
420 hashCode();
421
422 return;
423 }
424 }
425
426
427
428
429
430
431
432
433
434
435 public Rdn( SchemaManager schemaManager, Rdn rdn ) throws LdapInvalidDnException
436 {
437 nbAvas = rdn.size();
438 this.upName = rdn.getName();
439 this.schemaManager = schemaManager;
440 normalized = rdn.normalized;
441
442 switch ( rdn.size() )
443 {
444 case 0:
445 hashCode();
446
447 return;
448
449 case 1:
450 ava = new Ava( schemaManager, rdn.ava );
451
452 StringBuilder sb = new StringBuilder();
453
454 sb.append( ava.getNormType() );
455 sb.append( '=' );
456
457 if ( ( ava.getValue() != null ) && ( ava.getValue().getNormalized() != null ) )
458 {
459 sb.append( ava.getValue().getNormalized() );
460 }
461
462 normName = sb.toString();
463 normalized = true;
464
465 hashCode();
466
467 return;
468
469 default:
470
471 avas = new ArrayList<>();
472 avaTypes = new HashMap<>();
473 sb = new StringBuilder();
474 boolean isFirst = true;
475
476 for ( Ava currentAva : rdn.avas )
477 {
478 Ava tmpAva = currentAva;
479
480 if ( !currentAva.isSchemaAware() && ( schemaManager != null ) )
481 {
482 tmpAva = new Ava( schemaManager, currentAva );
483 }
484
485 List<Ava> avaList = avaTypes.get( tmpAva.getNormType() );
486
487 boolean empty = avaList == null;
488 avaList = addOrdered( avaList, tmpAva );
489
490 if ( empty )
491 {
492 avaTypes.put( tmpAva.getNormType(), avaList );
493 }
494
495 addOrdered( avas, tmpAva );
496 }
497
498 for ( Ava ava : avas )
499 {
500 if ( isFirst )
501 {
502 isFirst = false;
503 }
504 else
505 {
506 sb.append( '+' );
507 }
508
509 sb.append( ava.getNormType() );
510 sb.append( '=' );
511
512 if ( ( ava.getValue() != null ) && ( ava.getValue().getNormalized() != null ) )
513 {
514 sb.append( ava.getValue().getNormalized() );
515 }
516 }
517
518 normName = sb.toString();
519 normalized = true;
520
521 hashCode();
522
523 return;
524 }
525 }
526
527
528
529
530
531
532
533
534
535 static List<Ava> addOrdered( List<Ava> avaList, Ava newAva ) throws LdapInvalidDnException
536 {
537 if ( avaList == null )
538 {
539 avaList = new ArrayList<>();
540 }
541
542 if ( avaList.isEmpty() )
543 {
544 avaList.add( newAva );
545
546 return avaList;
547 }
548
549
550 int pos = 0;
551 boolean found = false;
552
553 for ( Ava avaElem : avaList )
554 {
555 int comp = newAva.compareTo( avaElem );
556
557 if ( comp < 0 )
558 {
559 avaList.add( pos, newAva );
560 found = true;
561 break;
562 }
563 else if ( comp == 0 )
564 {
565 found = true;
566
567 throw new LdapInvalidDnException( I18n.err( I18n.ERR_13626_INVALID_RDN_DUPLICATE_AVA, avaElem.normType ) );
568 }
569 else
570 {
571 pos++;
572 }
573 }
574
575 if ( !found )
576 {
577 avaList.add( newAva );
578 }
579
580 return avaList;
581 }
582
583
584
585
586
587
588
589
590
591
592 private void addAVA( SchemaManager schemaManager, String type, Value value ) throws LdapInvalidDnException
593 {
594
595 AttributeType attributeType;
596 String normalizedType = Strings.lowerCaseAscii( type );
597 this.schemaManager = schemaManager;
598
599 if ( schemaManager != null )
600 {
601 attributeType = schemaManager.getAttributeType( normalizedType );
602
603 if ( !value.isSchemaAware() )
604 {
605 if ( attributeType != null )
606 {
607 try
608 {
609 value = new Value( attributeType, value );
610 }
611 catch ( LdapInvalidAttributeValueException liave )
612 {
613 throw new LdapInvalidDnException( liave.getMessage(), liave );
614 }
615 }
616 }
617 else
618 {
619 if ( attributeType != null )
620 {
621 normalizedType = attributeType.getOid();
622 }
623 }
624 }
625
626 Ava newAva = new Ava( schemaManager, type, normalizedType, value );
627
628 switch ( nbAvas )
629 {
630 case 0:
631
632 ava = newAva;
633 nbAvas = 1;
634 avaType = normalizedType;
635 hashCode();
636
637 return;
638
639 case 1:
640
641
642 if ( ava.equals( newAva ) )
643 {
644 return;
645 }
646
647
648 avas = new ArrayList<>();
649 avaTypes = new HashMap<>();
650 List<Ava> avaList = new ArrayList<>();
651
652
653 avas.add( ava );
654 avaList.add( ava );
655 avaTypes.put( avaType, avaList );
656 nbAvas++;
657
658 ava = null;
659
660
661
662
663 default:
664
665 avaList = avaTypes.get( newAva.getNormType() );
666
667 if ( avaList == null )
668 {
669
670 avaList = new ArrayList<>();
671 avaList.add( newAva );
672 avaTypes.put( newAva.getNormType(), avaList );
673 avas.add( newAva );
674 nbAvas++;
675 }
676 else
677 {
678
679 if ( !avaList.contains( newAva ) )
680 {
681
682 avaList.add( newAva );
683 avas.add( newAva );
684 nbAvas++;
685 }
686 }
687 }
688 }
689
690
691
692
693
694
695
696
697
698
699
700
701 void addAVA( SchemaManager schemaManager, Ava addedAva ) throws LdapInvalidDnException
702 {
703 this.schemaManager = schemaManager;
704
705 if ( !addedAva.isSchemaAware() && ( schemaManager != null ) )
706 {
707 addedAva = new Ava( schemaManager, addedAva );
708 }
709
710 String normalizedType = addedAva.getNormType();
711
712 switch ( nbAvas )
713 {
714 case 0:
715
716 ava = addedAva;
717 nbAvas = 1;
718 avaType = normalizedType;
719 hashCode();
720
721 return;
722
723 case 1:
724
725
726
727 if ( ava.equals( addedAva ) )
728 {
729 throw new LdapInvalidDnException( I18n.err( I18n.ERR_13626_INVALID_RDN_DUPLICATE_AVA, normalizedType ) );
730 }
731
732
733 avas = new ArrayList<>();
734 avaTypes = new HashMap<>();
735 List<Ava> avaList = new ArrayList<>();
736
737
738 avas.add( ava );
739 avaList.add( ava );
740 avaTypes.put( ava.getNormType(), avaList );
741
742 this.ava = null;
743
744
745
746
747 default:
748
749 avaList = avaTypes.get( addedAva.getNormType() );
750
751 if ( avaList == null )
752 {
753
754 avaList = new ArrayList<>();
755 avaList.add( addedAva );
756 avaTypes.put( addedAva.getNormType(), avaList );
757 avas.add( addedAva );
758 nbAvas++;
759 }
760 else
761 {
762
763 addOrdered( avaList, addedAva );
764
765 boolean found = false;
766
767 for ( int pos = 0; pos < avas.size(); pos++ )
768 {
769 int comp = addedAva.compareTo( avas.get( pos ) );
770
771 if ( comp < 0 )
772 {
773 avas.add( pos, addedAva );
774 found = true;
775 nbAvas++;
776 break;
777 }
778 else if ( comp == 0 )
779 {
780 found = true;
781 break;
782 }
783 }
784
785
786 if ( !found )
787 {
788 avas.add( addedAva );
789 nbAvas++;
790 }
791 }
792
793 break;
794 }
795 }
796
797
798
799
800
801
802
803
804 void clear()
805 {
806 ava = null;
807 avas = null;
808 avaType = null;
809 avaTypes = null;
810 nbAvas = 0;
811 upName = "";
812 normalized = false;
813 h = 0;
814 }
815
816
817
818
819
820
821
822
823
824
825 public Object getValue( String type ) throws LdapInvalidDnException
826 {
827
828 String normalizedType = Strings.lowerCaseAscii( Strings.trim( type ) );
829
830 if ( schemaManager != null )
831 {
832 AttributeType attributeType = schemaManager.getAttributeType( normalizedType );
833
834 if ( attributeType != null )
835 {
836 normalizedType = attributeType.getOid();
837 }
838 }
839
840 switch ( nbAvas )
841 {
842 case 0:
843 return "";
844
845 case 1:
846 if ( ava.getNormType().equals( normalizedType ) )
847 {
848 if ( ava.getValue() != null )
849 {
850 return ava.getValue().getString();
851 }
852 else
853 {
854 return null;
855 }
856 }
857
858 return "";
859
860 default:
861 List<Ava> avaList = avaTypes.get( normalizedType );
862
863 if ( avaList != null )
864 {
865 for ( Ava elem : avaList )
866 {
867 if ( elem.getNormType().equals( normalizedType ) )
868 {
869 if ( elem.getValue() != null )
870 {
871 return elem.getValue().getString();
872 }
873 else
874 {
875 return null;
876 }
877 }
878 }
879
880 return null;
881 }
882
883 return null;
884 }
885 }
886
887
888
889
890
891
892
893
894
895
896 public Ava getAva( String type )
897 {
898
899 String normalizedType = Strings.lowerCaseAscii( Strings.trim( type ) );
900
901 switch ( nbAvas )
902 {
903 case 0:
904 return null;
905
906 case 1:
907 if ( ava.getNormType().equals( normalizedType ) )
908 {
909 return ava;
910 }
911
912 return null;
913
914 default:
915 List<Ava> avaList = avaTypes.get( normalizedType );
916
917 if ( avaList != null )
918 {
919 return avaList.get( 0 );
920 }
921
922 return null;
923 }
924 }
925
926
927
928
929
930
931
932
933
934 @Override
935 public Iterator<Ava> iterator()
936 {
937 if ( nbAvas < 2 )
938 {
939 return new Iterator<Ava>()
940 {
941 private boolean hasMoreElement = nbAvas == 1;
942
943
944 @Override
945 public boolean hasNext()
946 {
947 return hasMoreElement;
948 }
949
950
951 @Override
952 public Ava next()
953 {
954 Ava obj = ava;
955 hasMoreElement = false;
956 return obj;
957 }
958
959
960 @Override
961 public void remove()
962 {
963
964 }
965 };
966 }
967 else
968 {
969 return avas.iterator();
970 }
971 }
972
973
974
975
976
977
978
979 @Override
980 public Rdn clone()
981 {
982 try
983 {
984 Rdn rdn = ( Rdn ) super.clone();
985 rdn.normalized = normalized;
986
987
988
989 switch ( rdn.size() )
990 {
991 case 0:
992 break;
993
994 case 1:
995 rdn.ava = this.ava.clone();
996 rdn.avaTypes = avaTypes;
997 break;
998
999 default:
1000
1001 rdn.avaTypes = new HashMap<>();
1002 rdn.avas = new ArrayList<>();
1003
1004 for ( Ava currentAva : this.avas )
1005 {
1006 rdn.avas.add( currentAva.clone() );
1007 List<Ava> avaList = new ArrayList<>();
1008
1009 for ( Ava elem : avaTypes.get( currentAva.getNormType() ) )
1010 {
1011 avaList.add( elem.clone() );
1012 }
1013
1014 rdn.avaTypes.put( currentAva.getNormType(), avaList );
1015 }
1016
1017 break;
1018 }
1019
1020 return rdn;
1021 }
1022 catch ( CloneNotSupportedException cnse )
1023 {
1024 throw new Error( I18n.err( I18n.ERR_13621_ASSERTION_FAILURE ), cnse );
1025 }
1026 }
1027
1028
1029
1030
1031
1032 public String getName()
1033 {
1034 return upName;
1035 }
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045 void setUpName( String upName )
1046 {
1047 this.upName = upName;
1048 }
1049
1050
1051
1052
1053
1054 public String getNormName()
1055 {
1056 return normName;
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067 void setNormName( String normName )
1068 {
1069 this.normName = normName;
1070 normalized = true;
1071 }
1072
1073
1074
1075
1076
1077
1078
1079
1080 public Ava getAva()
1081 {
1082 switch ( nbAvas )
1083 {
1084 case 0:
1085 return null;
1086
1087 case 1:
1088 return ava;
1089
1090 default:
1091 return avas.get( 0 );
1092 }
1093 }
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103 public Ava getAva( int pos )
1104 {
1105 if ( pos > nbAvas )
1106 {
1107 return null;
1108 }
1109
1110 if ( pos == 0 )
1111 {
1112 if ( nbAvas == 1 )
1113 {
1114 return ava;
1115 }
1116 else
1117 {
1118 return avas.get( 0 );
1119 }
1120 }
1121 else
1122 {
1123 return avas.get( pos );
1124 }
1125 }
1126
1127
1128
1129
1130
1131
1132
1133 public String getType()
1134 {
1135 switch ( nbAvas )
1136 {
1137 case 0:
1138 return null;
1139
1140 case 1:
1141 return ava.getType();
1142
1143 default:
1144 return avas.get( 0 ).getType();
1145 }
1146 }
1147
1148
1149
1150
1151
1152
1153
1154 public String getNormType()
1155 {
1156 switch ( nbAvas )
1157 {
1158 case 0:
1159 return null;
1160
1161 case 1:
1162 return ava.getNormType();
1163
1164 default:
1165 return avas.get( 0 ).getNormType();
1166 }
1167 }
1168
1169
1170
1171
1172
1173
1174
1175 public String getValue()
1176 {
1177 switch ( nbAvas )
1178 {
1179 case 0:
1180 return null;
1181
1182 case 1:
1183 return ava.getValue().getString();
1184
1185 default:
1186 return avas.get( 0 ).getValue().getString();
1187 }
1188 }
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200 @Override
1201 public boolean equals( Object that )
1202 {
1203 if ( this == that )
1204 {
1205 return true;
1206 }
1207
1208 Rdn rdn;
1209
1210 if ( that instanceof String )
1211 {
1212 try
1213 {
1214 rdn = new Rdn( schemaManager, ( String ) that );
1215 }
1216 catch ( LdapInvalidDnException e )
1217 {
1218 return false;
1219 }
1220 }
1221 else if ( !( that instanceof Rdn ) )
1222 {
1223 return false;
1224 }
1225 else
1226 {
1227 rdn = ( Rdn ) that;
1228 }
1229
1230 if ( rdn.nbAvas != nbAvas )
1231 {
1232
1233
1234
1235 return false;
1236 }
1237
1238 switch ( nbAvas )
1239 {
1240 case 0:
1241 return true;
1242
1243 case 1:
1244 return ava.equals( rdn.ava );
1245
1246 default:
1247
1248
1249
1250
1251
1252
1253 for ( Ava paramAva : rdn.avas )
1254 {
1255 List<Ava> avaList = avaTypes.get( paramAva.getNormType() );
1256
1257 if ( ( avaList == null ) || !avaList.contains( paramAva ) )
1258 {
1259 return false;
1260 }
1261 }
1262
1263 return true;
1264 }
1265 }
1266
1267
1268
1269
1270
1271
1272
1273 public int size()
1274 {
1275 return nbAvas;
1276 }
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298 public static Object unescapeValue( String value )
1299 {
1300 if ( Strings.isEmpty( value ) )
1301 {
1302 return "";
1303 }
1304
1305 char[] chars = value.toCharArray();
1306
1307
1308 if ( ( chars[0] == '\"' ) && ( chars[chars.length - 1] == '\"' ) )
1309 {
1310 return new String( chars, 1, chars.length - 2 );
1311 }
1312
1313 if ( chars[0] == '#' )
1314 {
1315 if ( chars.length == 1 )
1316 {
1317
1318 return Strings.EMPTY_BYTES;
1319 }
1320
1321 if ( ( chars.length % 2 ) != 1 )
1322 {
1323 throw new IllegalArgumentException( I18n.err( I18n.ERR_13613_VALUE_NOT_IN_HEX_FORM_ODD_NUMBER ) );
1324 }
1325
1326
1327 byte[] hexValue = new byte[( chars.length - 1 ) / 2];
1328 int pos = 0;
1329
1330 for ( int i = 1; i < chars.length; i += 2 )
1331 {
1332 if ( Chars.isHex( chars, i ) && Chars.isHex( chars, i + 1 ) )
1333 {
1334 hexValue[pos++] = Hex.getHexValue( chars[i], chars[i + 1] );
1335 }
1336 else
1337 {
1338 throw new IllegalArgumentException( I18n.err( I18n.ERR_13614_VALUE_NOT_IN_HEX_FORM ) );
1339 }
1340 }
1341
1342 return hexValue;
1343 }
1344 else
1345 {
1346 boolean escaped = false;
1347 boolean isHex = false;
1348 byte pair = -1;
1349 int pos = 0;
1350
1351 byte[] bytes = new byte[chars.length * 6];
1352
1353 for ( int i = 0; i < chars.length; i++ )
1354 {
1355 if ( escaped )
1356 {
1357 escaped = false;
1358
1359 switch ( chars[i] )
1360 {
1361 case '\\':
1362 case '"':
1363 case '+':
1364 case ',':
1365 case ';':
1366 case '<':
1367 case '>':
1368 case '#':
1369 case '=':
1370 case ' ':
1371 bytes[pos++] = ( byte ) chars[i];
1372 break;
1373
1374 default:
1375 if ( Chars.isHex( chars, i ) )
1376 {
1377 isHex = true;
1378 pair = ( byte ) ( Hex.getHexValue( chars[i] ) << 4 );
1379 }
1380
1381 break;
1382 }
1383 }
1384 else
1385 {
1386 if ( isHex )
1387 {
1388 if ( Chars.isHex( chars, i ) )
1389 {
1390 pair += Hex.getHexValue( chars[i] );
1391 bytes[pos++] = pair;
1392 isHex = false;
1393 pair = 0;
1394 }
1395 }
1396 else
1397 {
1398 switch ( chars[i] )
1399 {
1400 case '\\':
1401 escaped = true;
1402 break;
1403
1404
1405
1406
1407 case '"':
1408 case '+':
1409 case ',':
1410 case ';':
1411 case '<':
1412 case '>':
1413 case '#':
1414 if ( i != 0 )
1415 {
1416
1417 bytes[pos++] = '#';
1418 }
1419
1420 break;
1421
1422 case ' ':
1423 if ( ( i == 0 ) || ( i == chars.length - 1 ) )
1424 {
1425 throw new IllegalArgumentException( I18n.err( I18n.ERR_13615_UNESCAPED_CHARS_NOT_ALLOWED ) );
1426 }
1427 else
1428 {
1429 bytes[pos++] = ' ';
1430 break;
1431 }
1432
1433 default:
1434 if ( chars[i] < 128 )
1435 {
1436 bytes[pos++] = ( byte ) chars[i];
1437 }
1438 else
1439 {
1440 byte[] result = Unicode.charToBytes( chars[i] );
1441 System.arraycopy( result, 0, bytes, pos, result.length );
1442 pos += result.length;
1443 }
1444
1445 break;
1446 }
1447 }
1448 }
1449 }
1450
1451 return Strings.utf8ToString( bytes, pos );
1452 }
1453 }
1454
1455
1456
1457
1458
1459
1460
1461
1462 public static String escapeValue( String value )
1463 {
1464 if ( Strings.isEmpty( value ) )
1465 {
1466 return "";
1467 }
1468
1469 char[] chars = value.toCharArray();
1470 char[] newChars = new char[chars.length * 3];
1471 int pos = 0;
1472
1473 for ( int i = 0; i < chars.length; i++ )
1474 {
1475 switch ( chars[i] )
1476 {
1477 case ' ':
1478 if ( ( i > 0 ) && ( i < chars.length - 1 ) )
1479 {
1480 newChars[pos++] = chars[i];
1481 }
1482 else
1483 {
1484 newChars[pos++] = '\\';
1485 newChars[pos++] = chars[i];
1486 }
1487
1488 break;
1489
1490 case '#':
1491 if ( i != 0 )
1492 {
1493 newChars[pos++] = chars[i];
1494 }
1495 else
1496 {
1497 newChars[pos++] = '\\';
1498 newChars[pos++] = chars[i];
1499 }
1500
1501 break;
1502
1503 case '"':
1504 case '+':
1505 case ',':
1506 case ';':
1507 case '=':
1508 case '<':
1509 case '>':
1510 case '\\':
1511 newChars[pos++] = '\\';
1512 newChars[pos++] = chars[i];
1513 break;
1514
1515 case 0x7F:
1516 newChars[pos++] = '\\';
1517 newChars[pos++] = '7';
1518 newChars[pos++] = 'F';
1519 break;
1520
1521 case 0x00:
1522 case 0x01:
1523 case 0x02:
1524 case 0x03:
1525 case 0x04:
1526 case 0x05:
1527 case 0x06:
1528 case 0x07:
1529 case 0x08:
1530 case 0x09:
1531 case 0x0A:
1532 case 0x0B:
1533 case 0x0C:
1534 case 0x0D:
1535 case 0x0E:
1536 case 0x0F:
1537 newChars[pos++] = '\\';
1538 newChars[pos++] = '0';
1539 newChars[pos++] = Strings.dumpHex( ( byte ) ( chars[i] & 0x0F ) );
1540 break;
1541
1542 case 0x10:
1543 case 0x11:
1544 case 0x12:
1545 case 0x13:
1546 case 0x14:
1547 case 0x15:
1548 case 0x16:
1549 case 0x17:
1550 case 0x18:
1551 case 0x19:
1552 case 0x1A:
1553 case 0x1B:
1554 case 0x1C:
1555 case 0x1D:
1556 case 0x1E:
1557 case 0x1F:
1558 newChars[pos++] = '\\';
1559 newChars[pos++] = '1';
1560 newChars[pos++] = Strings.dumpHex( ( byte ) ( chars[i] & 0x0F ) );
1561 break;
1562
1563 default:
1564 newChars[pos++] = chars[i];
1565 break;
1566 }
1567 }
1568
1569 return new String( newChars, 0, pos );
1570 }
1571
1572
1573
1574
1575
1576 public String getEscaped()
1577 {
1578 StringBuilder sb = new StringBuilder();
1579
1580 switch ( nbAvas )
1581 {
1582 case 0:
1583 return "";
1584
1585 case 1:
1586 sb.append( ava.getEscaped() );
1587
1588 break;
1589
1590 default:
1591 boolean isFirst = true;
1592
1593 for ( Ava atav : avas )
1594 {
1595 if ( isFirst )
1596 {
1597 isFirst = false;
1598 }
1599 else
1600 {
1601 sb.append( '+' );
1602 }
1603
1604 sb.append( atav.getEscaped() );
1605 }
1606
1607 break;
1608 }
1609
1610 return sb.toString();
1611 }
1612
1613
1614
1615
1616
1617
1618
1619
1620 public static String escapeValue( byte[] attrValue )
1621 {
1622 if ( Strings.isEmpty( attrValue ) )
1623 {
1624 return "";
1625 }
1626
1627 String value = Strings.utf8ToString( attrValue );
1628
1629 return escapeValue( value );
1630 }
1631
1632
1633
1634
1635
1636
1637
1638 public boolean isSchemaAware()
1639 {
1640 return schemaManager != null;
1641 }
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654 public static boolean isValid( String rdn )
1655 {
1656 try
1657 {
1658 parse( null, rdn, null );
1659
1660 return true;
1661 }
1662 catch ( LdapInvalidDnException e )
1663 {
1664 return false;
1665 }
1666 }
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680 public static boolean isValid( SchemaManager schemaManager, String rdn )
1681 {
1682 try
1683 {
1684 parse( schemaManager, rdn, null );
1685
1686 return true;
1687 }
1688 catch ( LdapInvalidDnException e )
1689 {
1690 return false;
1691 }
1692 }
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708 private static void parse( SchemaManager schemaManager, String rdnStr, Rdn rdn ) throws LdapInvalidDnException
1709 {
1710 try
1711 {
1712 FastDnParser.parseRdn( schemaManager, rdnStr, rdn );
1713 }
1714 catch ( TooComplexDnException e )
1715 {
1716 if ( rdn != null )
1717 {
1718 rdn.clear();
1719 }
1720 else
1721 {
1722 rdn = new Rdn();
1723 }
1724
1725 new ComplexDnParser().parseRdn( schemaManager, rdnStr, rdn );
1726 }
1727 }
1728
1729
1730
1731
1732
1733
1734
1735
1736 @Override
1737 public int hashCode()
1738 {
1739 if ( h == 0 )
1740 {
1741 int hTmp = 37;
1742
1743 switch ( nbAvas )
1744 {
1745 case 0:
1746
1747 break;
1748
1749 case 1:
1750
1751 h = hTmp * 17 + ava.hashCode();
1752 break;
1753
1754 default:
1755
1756
1757 for ( Ava ata : avas )
1758 {
1759 h = hTmp * 17 + ata.hashCode();
1760 }
1761
1762 break;
1763 }
1764 }
1765
1766 return h;
1767 }
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778 public int serialize( byte[] buffer, int pos ) throws IOException
1779 {
1780
1781 int length = 4 + 4;
1782
1783
1784 pos = Serialize.serialize( nbAvas, buffer, pos );
1785
1786
1787 byte[] upNameBytes = Strings.getBytesUtf8( upName );
1788 length += 4 + upNameBytes.length;
1789
1790
1791 if ( buffer.length - pos < length )
1792 {
1793 throw new ArrayIndexOutOfBoundsException();
1794 }
1795
1796
1797 pos = Serialize.serialize( upNameBytes, buffer, pos );
1798
1799
1800 switch ( nbAvas )
1801 {
1802 case 0:
1803 break;
1804
1805 case 1:
1806 pos = ava.serialize( buffer, pos );
1807
1808 break;
1809
1810 default:
1811 for ( Ava localAva : avas )
1812 {
1813 pos = localAva.serialize( buffer, pos );
1814 }
1815
1816 break;
1817 }
1818
1819
1820 pos = Serialize.serialize( h, buffer, pos );
1821
1822 return pos;
1823 }
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835 public int deserialize( byte[] buffer, int pos ) throws IOException, LdapInvalidAttributeValueException
1836 {
1837 if ( ( pos < 0 ) || ( pos >= buffer.length ) )
1838 {
1839 throw new ArrayIndexOutOfBoundsException();
1840 }
1841
1842
1843 nbAvas = Serialize.deserializeInt( buffer, pos );
1844 pos += 4;
1845
1846
1847 byte[] upNameBytes = Serialize.deserializeBytes( buffer, pos );
1848 pos += 4 + upNameBytes.length;
1849 upName = Strings.utf8ToString( upNameBytes );
1850
1851
1852 switch ( nbAvas )
1853 {
1854 case 0:
1855 break;
1856
1857 case 1:
1858 ava = new Ava( schemaManager );
1859 pos = ava.deserialize( buffer, pos );
1860 avaType = ava.getNormType();
1861
1862 break;
1863
1864 default:
1865 avas = new ArrayList<>();
1866 avaTypes = new HashMap<>();
1867
1868 for ( int i = 0; i < nbAvas; i++ )
1869 {
1870 Ava newAva = new Ava( schemaManager );
1871 pos = newAva.deserialize( buffer, pos );
1872 avas.add( newAva );
1873
1874 List<Ava> avaList = avaTypes.get( newAva.getNormType() );
1875
1876 if ( avaList == null )
1877 {
1878 avaList = new ArrayList<>();
1879 avaTypes.put( newAva.getNormType(), avaList );
1880 }
1881
1882 avaList.add( newAva );
1883 }
1884
1885 ava = null;
1886 avaType = null;
1887
1888 break;
1889 }
1890
1891
1892 h = Serialize.deserializeInt( buffer, pos );
1893 pos += 4;
1894
1895 return pos;
1896 }
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935 @Override
1936 public void writeExternal( ObjectOutput out ) throws IOException
1937 {
1938 out.writeInt( nbAvas );
1939 out.writeUTF( upName );
1940
1941 switch ( nbAvas )
1942 {
1943 case 0:
1944 break;
1945
1946 case 1:
1947 ava.writeExternal( out );
1948 break;
1949
1950 default:
1951 for ( Ava localAva : avas )
1952 {
1953 localAva.writeExternal( out );
1954 }
1955
1956 break;
1957 }
1958
1959 out.writeInt( h );
1960
1961 out.flush();
1962 }
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975 @Override
1976 public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
1977 {
1978 StringBuilder sb = new StringBuilder();
1979
1980
1981 nbAvas = in.readInt();
1982
1983
1984 upName = in.readUTF();
1985
1986 switch ( nbAvas )
1987 {
1988 case 0:
1989 ava = null;
1990 normName = "";
1991 break;
1992
1993 case 1:
1994 ava = new Ava( schemaManager );
1995 ava.readExternal( in );
1996 avaType = ava.getNormType();
1997
1998 buildNormRdn( sb, ava );
1999 normName = sb.toString();
2000
2001 break;
2002
2003 default:
2004 avas = new ArrayList<>();
2005 avaTypes = new HashMap<>();
2006 boolean isFirst = true;
2007
2008 for ( int i = 0; i < nbAvas; i++ )
2009 {
2010 Ava newAva = new Ava( schemaManager );
2011 newAva.readExternal( in );
2012 avas.add( newAva );
2013
2014 List<Ava> avaList = avaTypes.get( newAva.getNormType() );
2015
2016 if ( avaList == null )
2017 {
2018 avaList = new ArrayList<>();
2019 avaTypes.put( newAva.getNormType(), avaList );
2020 }
2021
2022 if ( isFirst )
2023 {
2024 isFirst = false;
2025 }
2026 else
2027 {
2028 sb.append( '+' );
2029 }
2030
2031 buildNormRdn( sb, newAva );
2032
2033 avaList.add( newAva );
2034 }
2035
2036 ava = null;
2037 avaType = null;
2038 normName = sb.toString();
2039
2040 break;
2041 }
2042
2043 h = in.readInt();
2044 }
2045
2046
2047 private void buildNormRdn( StringBuilder sb, Ava ava )
2048 {
2049 sb.append( ava.getNormType() );
2050
2051 sb.append( '=' );
2052
2053 Value val = ava.getValue();
2054
2055 if ( ( val != null ) && ( val.getNormalized() != null ) )
2056 {
2057 sb.append( ava.getValue().getNormalized() );
2058 }
2059 }
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069 @Override
2070 public int compareTo( Rdn otherRdn )
2071 {
2072 if ( otherRdn == null )
2073 {
2074 return 1;
2075 }
2076
2077 if ( nbAvas < otherRdn.nbAvas )
2078 {
2079 return -1;
2080 }
2081 else if ( nbAvas > otherRdn.nbAvas )
2082 {
2083 return 1;
2084 }
2085
2086 switch ( nbAvas )
2087 {
2088 case 0 :
2089 return 0;
2090
2091 case 1 :
2092 int comp = ava.compareTo( otherRdn.ava );
2093
2094 if ( comp < 0 )
2095 {
2096 return -1;
2097 }
2098 else if ( comp > 0 )
2099 {
2100 return 1;
2101 }
2102 else
2103 {
2104 return 0;
2105 }
2106
2107 default :
2108
2109 if ( isSchemaAware() )
2110 {
2111 return normName.compareTo( otherRdn.normName );
2112 }
2113
2114 int pos = 0;
2115
2116 for ( Ava atav : avas )
2117 {
2118 Ava otherAva = otherRdn.avas.get( pos );
2119
2120 comp = atav.compareTo( otherAva );
2121
2122 if ( comp != 0 )
2123 {
2124 if ( comp < 0 )
2125 {
2126 return -1;
2127 }
2128 else
2129 {
2130 return 1;
2131 }
2132 }
2133
2134 pos++;
2135 }
2136
2137 return 0;
2138 }
2139 }
2140
2141
2142
2143
2144
2145
2146 @Override
2147 public String toString()
2148 {
2149 return upName == null ? "" : upName;
2150 }
2151 }