001 /*
002 * Copyright 2009-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2009-2016 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.migrate.jndi;
022
023
024
025 import java.util.Collection;
026 import javax.naming.NamingEnumeration;
027 import javax.naming.NamingException;
028 import javax.naming.directory.Attributes;
029 import javax.naming.directory.BasicAttribute;
030 import javax.naming.directory.BasicAttributes;
031 import javax.naming.directory.DirContext;
032 import javax.naming.directory.ModificationItem;
033 import javax.naming.directory.SearchResult;
034 import javax.naming.ldap.BasicControl;
035 import javax.naming.ldap.ExtendedResponse;
036
037 import com.unboundid.asn1.ASN1Exception;
038 import com.unboundid.asn1.ASN1OctetString;
039 import com.unboundid.ldap.sdk.Attribute;
040 import com.unboundid.ldap.sdk.Control;
041 import com.unboundid.ldap.sdk.DN;
042 import com.unboundid.ldap.sdk.Entry;
043 import com.unboundid.ldap.sdk.ExtendedRequest;
044 import com.unboundid.ldap.sdk.ExtendedResult;
045 import com.unboundid.ldap.sdk.Modification;
046 import com.unboundid.ldap.sdk.ModificationType;
047 import com.unboundid.ldap.sdk.RDN;
048 import com.unboundid.util.Debug;
049 import com.unboundid.util.NotMutable;
050 import com.unboundid.util.ThreadSafety;
051 import com.unboundid.util.ThreadSafetyLevel;
052
053 import static com.unboundid.util.StaticUtils.*;
054
055
056
057 /**
058 * This utility class provides a set of methods that may be used to convert
059 * between data structures in the Java Naming and Directory Interface (JNDI)
060 * and the corresponding data structures in the UnboundID LDAP SDK for Java.
061 */
062 @NotMutable()
063 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
064 public final class JNDIConverter
065 {
066 /**
067 * An empty array of attributes.
068 */
069 private static final Attribute[] NO_ATTRIBUTES = new Attribute[0];
070
071
072
073
074 /**
075 * An empty array of JNDI controls.
076 */
077 private static final javax.naming.ldap.Control[] NO_JNDI_CONTROLS =
078 new javax.naming.ldap.Control[0];
079
080
081
082 /**
083 * An empty array of SDK modifications.
084 */
085 private static final Modification[] NO_MODIFICATIONS = new Modification[0];
086
087
088
089 /**
090 * An empty array of JNDI modification items.
091 */
092 private static final ModificationItem[] NO_MODIFICATION_ITEMS =
093 new ModificationItem[0];
094
095
096
097
098 /**
099 * An empty array of SDK controls.
100 */
101 private static final Control[] NO_SDK_CONTROLS = new Control[0];
102
103
104
105
106 /**
107 * Prevent this utility class from being instantiated.
108 */
109 private JNDIConverter()
110 {
111 // No implementation required.
112 }
113
114
115
116 /**
117 * Converts the provided JNDI attribute to an LDAP SDK attribute.
118 *
119 * @param a The attribute to be converted.
120 *
121 * @return The LDAP SDK attribute that corresponds to the provided JNDI
122 * attribute.
123 *
124 * @throws NamingException If a problem is encountered during the conversion
125 * process.
126 */
127 public static Attribute convertAttribute(
128 final javax.naming.directory.Attribute a)
129 throws NamingException
130 {
131 if (a == null)
132 {
133 return null;
134 }
135
136 final String name = a.getID();
137 final ASN1OctetString[] values = new ASN1OctetString[a.size()];
138
139 for (int i=0; i < values.length; i++)
140 {
141 final Object value = a.get(i);
142 if (value instanceof byte[])
143 {
144 values[i] = new ASN1OctetString((byte[]) value);
145 }
146 else
147 {
148 values[i] = new ASN1OctetString(String.valueOf(value));
149 }
150 }
151
152 return new Attribute(name, values);
153 }
154
155
156
157 /**
158 * Converts the provided LDAP SDK attribute to a JNDI attribute.
159 *
160 * @param a The attribute to be converted.
161 *
162 * @return The JNDI attribute that corresponds to the provided LDAP SDK
163 * attribute.
164 */
165 public static javax.naming.directory.Attribute convertAttribute(
166 final Attribute a)
167 {
168 if (a == null)
169 {
170 return null;
171 }
172
173 final BasicAttribute attr = new BasicAttribute(a.getName(), true);
174 for (final String v : a.getValues())
175 {
176 attr.add(v);
177 }
178
179 return attr;
180 }
181
182
183
184 /**
185 * Converts the provided JNDI attributes to an array of LDAP SDK attributes.
186 *
187 * @param a The attributes to be converted.
188 *
189 * @return The array of LDAP SDK attributes that corresponds to the
190 * provided JNDI attributes.
191 *
192 * @throws NamingException If a problem is encountered during the conversion
193 * process.
194 */
195 public static Attribute[] convertAttributes(final Attributes a)
196 throws NamingException
197 {
198 if (a == null)
199 {
200 return NO_ATTRIBUTES;
201 }
202
203 int i=0;
204 final Attribute[] attributes = new Attribute[a.size()];
205 final NamingEnumeration<? extends javax.naming.directory.Attribute> e =
206 a.getAll();
207
208 try
209 {
210 while (e.hasMoreElements())
211 {
212 attributes[i++] = convertAttribute(e.next());
213 }
214 }
215 finally
216 {
217 e.close();
218 }
219
220 return attributes;
221 }
222
223
224
225 /**
226 * Converts the provided array of LDAP SDK attributes to a set of JNDI
227 * attributes.
228 *
229 * @param a The array of attributes to be converted.
230 *
231 * @return The JNDI attributes that corresponds to the provided LDAP SDK
232 * attributes.
233 */
234 public static Attributes convertAttributes(final Attribute... a)
235 {
236 final BasicAttributes attrs = new BasicAttributes(true);
237 if (a == null)
238 {
239 return attrs;
240 }
241
242 for (final Attribute attr : a)
243 {
244 attrs.put(convertAttribute(attr));
245 }
246
247 return attrs;
248 }
249
250
251
252 /**
253 * Converts the provided collection of LDAP SDK attributes to a set of JNDI
254 * attributes.
255 *
256 * @param a The collection of attributes to be converted.
257 *
258 * @return The JNDI attributes that corresponds to the provided LDAP SDK
259 * attributes.
260 */
261 public static Attributes convertAttributes(final Collection<Attribute> a)
262 {
263 final BasicAttributes attrs = new BasicAttributes(true);
264 if (a == null)
265 {
266 return attrs;
267 }
268
269 for (final Attribute attr : a)
270 {
271 attrs.put(convertAttribute(attr));
272 }
273
274 return attrs;
275 }
276
277
278
279 /**
280 * Converts the provided JNDI control to an LDAP SDK control.
281 *
282 * @param c The control to be converted.
283 *
284 * @return The LDAP SDK control that corresponds to the provided JNDI
285 * control.
286 *
287 * @throws NamingException If a problem is encountered during the conversion
288 * process.
289 */
290 public static Control convertControl(final javax.naming.ldap.Control c)
291 throws NamingException
292 {
293 if (c == null)
294 {
295 return null;
296 }
297
298 final ASN1OctetString value;
299 final byte[] valueBytes = c.getEncodedValue();
300 if ((valueBytes == null) || (valueBytes.length == 0))
301 {
302 value = null;
303 }
304 else
305 {
306 try
307 {
308 value = ASN1OctetString.decodeAsOctetString(valueBytes);
309 }
310 catch (ASN1Exception ae)
311 {
312 throw new NamingException(getExceptionMessage(ae));
313 }
314 }
315
316 return new Control(c.getID(), c.isCritical(), value);
317 }
318
319
320
321 /**
322 * Converts the provided LDAP SDK control to a JNDI control.
323 *
324 * @param c The control to be converted.
325 *
326 * @return The JNDI control that corresponds to the provided LDAP SDK
327 * control.
328 */
329 public static javax.naming.ldap.Control convertControl(final Control c)
330 {
331 if (c == null)
332 {
333 return null;
334 }
335
336 final ASN1OctetString value = c.getValue();
337 if (value == null)
338 {
339 return new BasicControl(c.getOID(), c.isCritical(), null);
340 }
341 else
342 {
343 return new BasicControl(c.getOID(), c.isCritical(), value.encode());
344 }
345 }
346
347
348
349 /**
350 * Converts the provided array of JNDI controls to an array of LDAP SDK
351 * controls.
352 *
353 * @param c The array of JNDI controls to be converted.
354 *
355 * @return The array of LDAP SDK controls that corresponds to the provided
356 * array of JNDI controls.
357 *
358 * @throws NamingException If a problem is encountered during the conversion
359 * process.
360 */
361 public static Control[] convertControls(final javax.naming.ldap.Control... c)
362 throws NamingException
363 {
364 if (c == null)
365 {
366 return NO_SDK_CONTROLS;
367 }
368
369 final Control[] controls = new Control[c.length];
370 for (int i=0; i < controls.length; i++)
371 {
372 controls[i] = convertControl(c[i]);
373 }
374
375 return controls;
376 }
377
378
379
380 /**
381 * Converts the provided array of LDAP SDK controls to an array of JNDI
382 * controls.
383 *
384 * @param c The array of LDAP SDK controls to be converted.
385 *
386 * @return The array of JNDI controls that corresponds to the provided array
387 * of LDAP SDK controls.
388 */
389 public static javax.naming.ldap.Control[] convertControls(final Control... c)
390 {
391 if (c == null)
392 {
393 return NO_JNDI_CONTROLS;
394 }
395
396 final javax.naming.ldap.Control[] controls =
397 new javax.naming.ldap.Control[c.length];
398 for (int i=0; i < controls.length; i++)
399 {
400 controls[i] = convertControl(c[i]);
401 }
402
403 return controls;
404 }
405
406
407
408 /**
409 * Converts the provided JNDI extended request to an LDAP SDK extended
410 * request.
411 *
412 * @param r The request to be converted.
413 *
414 * @return The LDAP SDK extended request that corresponds to the provided
415 * JNDI extended request.
416 *
417 * @throws NamingException If a problem is encountered during the conversion
418 * process.
419 */
420 public static ExtendedRequest convertExtendedRequest(
421 final javax.naming.ldap.ExtendedRequest r)
422 throws NamingException
423 {
424 if (r == null)
425 {
426 return null;
427 }
428
429 return JNDIExtendedRequest.toSDKExtendedRequest(r);
430 }
431
432
433
434 /**
435 * Converts the provided LDAP SDK extended request to a JNDI extended request.
436 *
437 * @param r The request to be converted.
438 *
439 * @return The JNDI extended request that corresponds to the provided LDAP
440 * SDK extended request.
441 */
442 public static javax.naming.ldap.ExtendedRequest convertExtendedRequest(
443 final ExtendedRequest r)
444 {
445 if (r == null)
446 {
447 return null;
448 }
449
450 return new JNDIExtendedRequest(r);
451 }
452
453
454
455 /**
456 * Converts the provided JNDI extended response to an LDAP SDK extended
457 * result.
458 *
459 * @param r The response to be converted.
460 *
461 * @return The LDAP SDK extended result that corresponds to the provided
462 * JNDI extended response.
463 *
464 * @throws NamingException If a problem is encountered during the conversion
465 * process.
466 */
467 public static ExtendedResult convertExtendedResponse(final ExtendedResponse r)
468 throws NamingException
469 {
470 if (r == null)
471 {
472 return null;
473 }
474
475 return JNDIExtendedResponse.toSDKExtendedResult(r);
476 }
477
478
479
480 /**
481 * Converts the provided LDAP SDK extended result to a JNDI extended response.
482 *
483 * @param r The result to be converted.
484 *
485 * @return The JNDI extended response that corresponds to the provided LDAP
486 * SDK extended result.
487 */
488 public static ExtendedResponse convertExtendedResult(final ExtendedResult r)
489 {
490 if (r == null)
491 {
492 return null;
493 }
494
495 return new JNDIExtendedResponse(r);
496 }
497
498
499
500 /**
501 * Converts the provided JNDI modification item to an LDAP SDK modification.
502 *
503 * @param m The JNDI modification item to be converted.
504 *
505 * @return The LDAP SDK modification that corresponds to the provided JNDI
506 * modification item.
507 *
508 * @throws NamingException If a problem is encountered during the conversion
509 * process.
510 */
511 public static Modification convertModification(final ModificationItem m)
512 throws NamingException
513 {
514 if (m == null)
515 {
516 return null;
517 }
518
519 final ModificationType modType;
520 switch (m.getModificationOp())
521 {
522 case DirContext.ADD_ATTRIBUTE:
523 modType = ModificationType.ADD;
524 break;
525 case DirContext.REMOVE_ATTRIBUTE:
526 modType = ModificationType.DELETE;
527 break;
528 case DirContext.REPLACE_ATTRIBUTE:
529 modType = ModificationType.REPLACE;
530 break;
531 default:
532 throw new NamingException("Unsupported modification type " + m);
533 }
534
535 final Attribute a = convertAttribute(m.getAttribute());
536
537 return new Modification(modType, a.getName(), a.getRawValues());
538 }
539
540
541
542 /**
543 * Converts the provided LDAP SDK modification to a JNDI modification item.
544 *
545 * @param m The LDAP SDK modification to be converted.
546 *
547 * @return The JNDI modification item that corresponds to the provided LDAP
548 * SDK modification.
549 *
550 * @throws NamingException If a problem is encountered during the conversion
551 * process.
552 */
553 public static ModificationItem convertModification(final Modification m)
554 throws NamingException
555 {
556 if (m == null)
557 {
558 return null;
559 }
560
561 final int modType;
562 switch (m.getModificationType().intValue())
563 {
564 case ModificationType.ADD_INT_VALUE:
565 modType = DirContext.ADD_ATTRIBUTE;
566 break;
567 case ModificationType.DELETE_INT_VALUE:
568 modType = DirContext.REMOVE_ATTRIBUTE;
569 break;
570 case ModificationType.REPLACE_INT_VALUE:
571 modType = DirContext.REPLACE_ATTRIBUTE;
572 break;
573 default:
574 throw new NamingException("Unsupported modification type " + m);
575 }
576
577 return new ModificationItem(modType, convertAttribute(m.getAttribute()));
578 }
579
580
581
582 /**
583 * Converts the provided array of JNDI modification items to an array of LDAP
584 * SDK modifications.
585 *
586 * @param m The array of JNDI modification items to be converted.
587 *
588 * @return The array of LDAP SDK modifications that corresponds to the
589 * provided array of JNDI modification items.
590 *
591 * @throws NamingException If a problem is encountered during the conversion
592 * process.
593 */
594 public static Modification[] convertModifications(final ModificationItem... m)
595 throws NamingException
596 {
597 if (m == null)
598 {
599 return NO_MODIFICATIONS;
600 }
601
602 final Modification[] mods = new Modification[m.length];
603 for (int i=0; i < m.length; i++)
604 {
605 mods[i] = convertModification(m[i]);
606 }
607
608 return mods;
609 }
610
611
612
613 /**
614 * Converts the provided array of LDAP SDK modifications to an array of JNDI
615 * modification items.
616 *
617 * @param m The array of LDAP SDK modifications to be converted.
618 *
619 * @return The array of JNDI modification items that corresponds to the
620 * provided array of LDAP SDK modifications.
621 *
622 * @throws NamingException If a problem is encountered during the conversion
623 * process.
624 */
625 public static ModificationItem[] convertModifications(final Modification... m)
626 throws NamingException
627 {
628 if (m == null)
629 {
630 return NO_MODIFICATION_ITEMS;
631 }
632
633 final ModificationItem[] mods = new ModificationItem[m.length];
634 for (int i=0; i < m.length; i++)
635 {
636 mods[i] = convertModification(m[i]);
637 }
638
639 return mods;
640 }
641
642
643
644 /**
645 * Converts the provided JNDI search result object to an LDAP SDK entry.
646 *
647 * @param r The JNDI search result object to be converted.
648 *
649 * @return The LDAP SDK entry that corresponds to the provided JNDI search
650 * result.
651 *
652 * @throws NamingException If a problem is encountered during the conversion
653 * process.
654 */
655 public static Entry convertSearchEntry(final SearchResult r)
656 throws NamingException
657 {
658 return convertSearchEntry(r, null);
659 }
660
661
662
663 /**
664 * Converts the provided JNDI search result object to an LDAP SDK entry.
665 *
666 * @param r The JNDI search result object to be converted.
667 * @param contextBaseDN The base DN for the JNDI context over which the
668 * search result was retrieved. If it is
669 * non-{@code null} and non-empty, then it will be
670 * appended to the result of the {@code getName} method
671 * to obtain the entry's full DN.
672 *
673 * @return The LDAP SDK entry that corresponds to the provided JNDI search
674 * result.
675 *
676 * @throws NamingException If a problem is encountered during the conversion
677 * process.
678 */
679 public static Entry convertSearchEntry(final SearchResult r,
680 final String contextBaseDN)
681 throws NamingException
682 {
683 if (r == null)
684 {
685 return null;
686 }
687
688 final String dn;
689 if ((contextBaseDN == null) || (contextBaseDN.length() == 0))
690 {
691 dn = r.getName();
692 }
693 else
694 {
695 final String name = r.getName();
696 if ((name == null) || (name.length() == 0))
697 {
698 dn = contextBaseDN;
699 }
700 else
701 {
702 dn = r.getName() + ',' + contextBaseDN;
703 }
704 }
705
706 return new Entry(dn, convertAttributes(r.getAttributes()));
707 }
708
709
710
711 /**
712 * Converts the provided LDAP SDK entry to a JNDI search result.
713 *
714 * @param e The entry to be converted to a JNDI search result.
715 *
716 * @return The JNDI search result that corresponds to the provided LDAP SDK
717 * entry.
718 */
719 public static SearchResult convertSearchEntry(final Entry e)
720 {
721 return convertSearchEntry(e, null);
722 }
723
724
725
726 /**
727 * Converts the provided LDAP SDK entry to a JNDI search result.
728 *
729 * @param e The entry to be converted to a JNDI search result.
730 * @param contextBaseDN The base DN for the JNDI context over which the
731 * search result was retrieved. If it is
732 * non-{@code null} and non-empty, then it will be
733 * removed from the end of the entry's DN in order to
734 * obtain the name for the {@code SearchResult} that is
735 * returned.
736 *
737 * @return The JNDI search result that corresponds to the provided LDAP SDK
738 * entry.
739 */
740 public static SearchResult convertSearchEntry(final Entry e,
741 final String contextBaseDN)
742 {
743 if (e == null)
744 {
745 return null;
746 }
747
748 String name = e.getDN();
749 if ((contextBaseDN != null) && (contextBaseDN.length() > 0))
750 {
751 try
752 {
753 final DN parsedEntryDN = e.getParsedDN();
754 final DN parsedBaseDN = new DN(contextBaseDN);
755 if (parsedEntryDN.equals(parsedBaseDN))
756 {
757 name = "";
758 }
759 else if (parsedEntryDN.isDescendantOf(parsedBaseDN, false))
760 {
761 final RDN[] entryRDNs = parsedEntryDN.getRDNs();
762 final RDN[] baseRDNs = parsedBaseDN.getRDNs();
763 final RDN[] remainingRDNs =
764 new RDN[entryRDNs.length - baseRDNs.length];
765 System.arraycopy(entryRDNs, 0, remainingRDNs, 0,
766 remainingRDNs.length);
767 name = new DN(remainingRDNs).toString();
768 }
769 }
770 catch (final Exception ex)
771 {
772 Debug.debugException(ex);
773 }
774 }
775
776 final Collection<Attribute> attrs = e.getAttributes();
777 final Attribute[] attributes = new Attribute[attrs.size()];
778 attrs.toArray(attributes);
779
780 return new SearchResult(name, null, convertAttributes(attributes));
781 }
782 }