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