1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ldap.core;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.Enumeration;
22 import java.util.Iterator;
23 import java.util.LinkedList;
24 import java.util.List;
25 import java.util.ListIterator;
26
27 import javax.naming.CompositeName;
28 import javax.naming.InvalidNameException;
29 import javax.naming.Name;
30 import javax.naming.ldap.Rdn;
31
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.springframework.ldap.BadLdapGrammarException;
36 import org.springframework.ldap.support.LdapUtils;
37 import org.springframework.ldap.support.ListComparator;
38 import org.springframework.util.Assert;
39
40
41
42
43
44
45
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 public class DistinguishedName implements Name {
97
98
99
100
101
102
103
104
105
106 public static final String SPACED_DN_FORMAT_PROPERTY = "org.springframework.ldap.core.spacedDnFormat";
107
108 private static final Log log = LogFactory.getLog(DistinguishedName.class);
109
110 private static final boolean COMPACT = true;
111
112 private static final boolean NON_COMPACT = false;
113
114 private static final long serialVersionUID = 3514344371999042586L;
115
116
117
118
119 public static final DistinguishedName EMPTY_PATH = new DistinguishedName(Collections.EMPTY_LIST);
120
121 private List names;
122
123
124
125
126 public DistinguishedName() {
127 names = new LinkedList();
128 }
129
130
131
132
133
134
135 public DistinguishedName(String path) {
136 if (StringUtils.isBlank(path)) {
137 names = new LinkedList();
138 }
139 else {
140 parse(path);
141 }
142 }
143
144
145
146
147
148
149
150 public DistinguishedName(List list) {
151 this.names = list;
152 }
153
154
155
156
157
158
159
160
161
162 public DistinguishedName(Name name) {
163 Assert.notNull(name, "name cannot be null");
164 if (name instanceof CompositeName) {
165 parse(LdapUtils.convertCompositeNameToString((CompositeName) name));
166 return;
167 }
168 names = new LinkedList();
169 for (int i = 0; i < name.size(); i++) {
170 names.add(new LdapRdn(name.get(i)));
171 }
172 }
173
174
175
176
177
178
179
180 protected void parse(String path) {
181 DnParser parser = DefaultDnParserFactory.createDnParser(unmangleCompositeName(path));
182 DistinguishedName dn;
183 try {
184 dn = parser.dn();
185 }
186 catch (ParseException e) {
187 throw new BadLdapGrammarException("Failed to parse DN", e);
188 }
189 catch (TokenMgrError e) {
190 throw new BadLdapGrammarException("Failed to parse DN", e);
191 }
192 this.names = dn.names;
193 }
194
195
196
197
198
199
200
201
202
203
204 private String unmangleCompositeName(String path) {
205 String tempPath;
206
207 if (path.startsWith("\"") && path.endsWith("\"")) {
208 tempPath = path.substring(1, path.length() - 1);
209 }
210 else {
211 tempPath = path;
212 }
213 return tempPath;
214 }
215
216
217
218
219
220
221
222 public LdapRdn getLdapRdn(int index) {
223 return (LdapRdn) names.get(index);
224 }
225
226
227
228
229
230
231
232
233
234
235 public LdapRdn getLdapRdn(String key) {
236 for (Iterator iter = names.iterator(); iter.hasNext();) {
237 LdapRdn rdn = (LdapRdn) iter.next();
238 if (StringUtils.equals(rdn.getKey(), key)) {
239 return rdn;
240 }
241 }
242
243 throw new IllegalArgumentException("No Rdn with the requested key: '" + key + "'");
244 }
245
246
247
248
249
250
251
252
253
254
255 public String getValue(String key) {
256 return getLdapRdn(key).getValue();
257 }
258
259
260
261
262
263
264
265 public List getNames() {
266 return names;
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280 public String toString() {
281 String spacedFormatting = System.getProperty(SPACED_DN_FORMAT_PROPERTY);
282 if (StringUtils.isBlank(spacedFormatting)) {
283 return format(COMPACT);
284 }
285 else {
286 return format(NON_COMPACT);
287 }
288 }
289
290
291
292
293
294
295
296
297
298 public String toCompactString() {
299 return format(COMPACT);
300 }
301
302
303
304
305
306
307
308
309 public String encode() {
310 return format(NON_COMPACT);
311 }
312
313 private String format(boolean compact) {
314
315 if (names.size() == 0)
316 return "";
317
318 StringBuffer buffer = new StringBuffer(256);
319
320 ListIterator i = names.listIterator(names.size());
321 while (i.hasPrevious()) {
322 LdapRdn rdn = (LdapRdn) i.previous();
323 buffer.append(rdn.getLdapEncoded());
324
325
326 if (i.hasPrevious()) {
327 if (compact) {
328 buffer.append(",");
329 }
330 else {
331 buffer.append(", ");
332
333 }
334 }
335 }
336
337 return buffer.toString();
338 }
339
340
341
342
343
344
345
346 public String toUrl() {
347 StringBuffer buffer = new StringBuffer(256);
348
349 for (int i = names.size() - 1; i >= 0; i--) {
350 LdapRdn n = (LdapRdn) names.get(i);
351 buffer.append(n.encodeUrl());
352 if (i > 0) {
353 buffer.append(",");
354 }
355 }
356 return buffer.toString();
357 }
358
359
360
361
362
363
364
365
366
367 public boolean contains(DistinguishedName path) {
368
369 List shortlist = path.getNames();
370
371
372 if (getNames().size() < shortlist.size())
373 return false;
374
375
376 if (shortlist.size() == 0)
377 return false;
378
379 Iterator longiter = getNames().iterator();
380 Iterator shortiter = shortlist.iterator();
381
382 LdapRdn longname = (LdapRdn) longiter.next();
383 LdapRdn shortname = (LdapRdn) shortiter.next();
384
385
386 while (!longname.equals(shortname) && longiter.hasNext()) {
387 longname = (LdapRdn) longiter.next();
388 }
389
390
391 if (!shortiter.hasNext() && longname.equals(shortname))
392 return true;
393 if (!longiter.hasNext())
394 return false;
395
396
397 while (longname.equals(shortname) && longiter.hasNext() && shortiter.hasNext()) {
398 longname = (LdapRdn) longiter.next();
399 shortname = (LdapRdn) shortiter.next();
400 }
401
402
403 if (!shortiter.hasNext() && longname.equals(shortname))
404 return true;
405 else
406 return false;
407
408 }
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424 public DistinguishedName append(DistinguishedName path) {
425 getNames().addAll(path.getNames());
426 return this;
427 }
428
429
430
431
432
433
434
435
436 public DistinguishedName append(String key, String value) {
437 add(key, value);
438 return this;
439 }
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454 public void prepend(DistinguishedName path) {
455 ListIterator i = path.getNames().listIterator(path.getNames().size());
456 while (i.hasPrevious()) {
457 names.add(0, i.previous());
458 }
459 }
460
461
462
463
464
465
466 public LdapRdn removeFirst() {
467 return (LdapRdn) names.remove(0);
468 }
469
470
471
472
473
474
475
476
477
478 public void removeFirst(Name path) {
479 if (path != null && this.startsWith(path)) {
480 for (int i = 0; i < path.size(); i++)
481 this.removeFirst();
482 }
483 }
484
485
486
487
488 public Object clone() {
489 try {
490 DistinguishedName result = (DistinguishedName) super.clone();
491 result.names = new LinkedList(names);
492 return result;
493 }
494 catch (CloneNotSupportedException e) {
495 log.fatal("CloneNotSupported thrown from superclass - this should not happen");
496 throw new RuntimeException("Fatal error in clone", e);
497 }
498 }
499
500
501
502
503 public boolean equals(Object obj) {
504
505
506 if (obj == null || obj.getClass() != this.getClass()) {
507 return false;
508 }
509
510 DistinguishedName name = (DistinguishedName) obj;
511
512
513 return getNames().equals(name.getNames());
514 }
515
516
517
518
519 public int hashCode() {
520 return this.getClass().hashCode() ^ getNames().hashCode();
521 }
522
523
524
525
526
527
528
529
530 public int compareTo(Object obj) {
531 DistinguishedName that = (DistinguishedName) obj;
532 ListComparator comparator = new ListComparator();
533 return comparator.compare(this.names, that.names);
534 }
535
536 public int size() {
537 return names.size();
538 }
539
540 public boolean isEmpty() {
541 return names.size() == 0;
542 }
543
544
545
546
547
548
549 public Enumeration getAll() {
550 LinkedList strings = new LinkedList();
551 for (Iterator iter = names.iterator(); iter.hasNext();) {
552 LdapRdn rdn = (LdapRdn) iter.next();
553 strings.add(rdn.getLdapEncoded());
554 }
555
556 return Collections.enumeration(strings);
557 }
558
559
560
561
562
563
564 public String get(int index) {
565 LdapRdn rdn = (LdapRdn) names.get(index);
566 return rdn.getLdapEncoded();
567 }
568
569
570
571
572
573
574 public Name getPrefix(int index) {
575 LinkedList newNames = new LinkedList();
576 for (int i = 0; i < index; i++) {
577 newNames.add(names.get(i));
578 }
579
580 return new DistinguishedName(newNames);
581 }
582
583
584
585
586
587
588 public Name getSuffix(int index) {
589 if (index > names.size()) {
590 throw new ArrayIndexOutOfBoundsException();
591 }
592
593 LinkedList newNames = new LinkedList();
594 for (int i = index; i < names.size(); i++) {
595 newNames.add(names.get(i));
596 }
597
598 return new DistinguishedName(newNames);
599 }
600
601
602
603
604
605
606 public boolean startsWith(Name name) {
607 if (name.size() == 0) {
608 return false;
609 }
610
611 DistinguishedName start = null;
612 if (name instanceof DistinguishedName) {
613 start = (DistinguishedName) name;
614 }
615 else {
616 return false;
617 }
618
619 if (start.size() > this.size()) {
620 return false;
621 }
622
623 Iterator longiter = names.iterator();
624 Iterator shortiter = start.getNames().iterator();
625
626 while (shortiter.hasNext()) {
627 Object longname = longiter.next();
628 Object shortname = shortiter.next();
629
630 if (!longname.equals(shortname)) {
631 return false;
632 }
633 }
634
635
636 return true;
637 }
638
639
640
641
642
643
644
645
646
647
648
649 public boolean endsWith(Name name) {
650 DistinguishedName path = null;
651 if (name instanceof DistinguishedName) {
652 path = (DistinguishedName) name;
653 }
654 else {
655 return false;
656 }
657
658 List shortlist = path.getNames();
659
660
661 if (getNames().size() < shortlist.size())
662 return false;
663
664
665 if (shortlist.size() == 0)
666 return false;
667
668 ListIterator longiter = getNames().listIterator(getNames().size());
669 ListIterator shortiter = shortlist.listIterator(shortlist.size());
670
671 while (shortiter.hasPrevious()) {
672 LdapRdn longname = (LdapRdn) longiter.previous();
673 LdapRdn shortname = (LdapRdn) shortiter.previous();
674
675 if (!longname.equals(shortname))
676 return false;
677 }
678
679
680 return true;
681
682 }
683
684
685
686
687
688
689 public Name addAll(Name name) throws InvalidNameException {
690 return addAll(names.size(), name);
691 }
692
693
694
695
696
697
698 public Name addAll(int arg0, Name name) throws InvalidNameException {
699 DistinguishedName distinguishedName = null;
700 try {
701 distinguishedName = (DistinguishedName) name;
702 }
703 catch (ClassCastException e) {
704 throw new InvalidNameException("Invalid name type");
705 }
706
707 names.addAll(arg0, distinguishedName.getNames());
708 return this;
709 }
710
711
712
713
714
715
716 public Name add(String string) throws InvalidNameException {
717 return add(names.size(), string);
718 }
719
720
721
722
723
724
725 public Name add(int index, String string) throws InvalidNameException {
726 try {
727 names.add(index, new LdapRdn(string));
728 }
729 catch (BadLdapGrammarException e) {
730 throw new InvalidNameException("Failed to parse rdn '" + string + "'");
731 }
732 return this;
733 }
734
735
736
737
738
739
740 public Object remove(int arg0) throws InvalidNameException {
741 LdapRdn rdn = (LdapRdn) names.remove(arg0);
742 return rdn.getLdapEncoded();
743 }
744
745
746
747
748
749
750 public LdapRdn removeLast() {
751 return (LdapRdn) names.remove(names.size() - 1);
752 }
753
754
755
756
757
758
759
760 public void add(String key, String value) {
761 names.add(new LdapRdn(key, value));
762 }
763
764
765
766
767
768
769 public void add(LdapRdn rdn) {
770 names.add(rdn);
771 }
772
773
774
775
776
777
778
779 public void add(int idx, LdapRdn rdn) {
780 names.add(idx, rdn);
781 }
782
783
784
785
786
787
788
789
790
791 public DistinguishedName immutableDistinguishedName() {
792 List listWithImmutableRdns = new ArrayList(names.size());
793 for (Iterator iterator = names.iterator(); iterator.hasNext();) {
794 LdapRdn rdn = (LdapRdn) iterator.next();
795 listWithImmutableRdns.add(rdn.immutableLdapRdn());
796 }
797
798 return new DistinguishedName(Collections.unmodifiableList(listWithImmutableRdns));
799 }
800
801
802
803
804
805
806
807
808
809 public static final DistinguishedName immutableDistinguishedName(String dnString) {
810 return new DistinguishedName(dnString).immutableDistinguishedName();
811 }
812 }