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