001    /*
002     * Copyright 2009-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-2015 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.Entry;
042    import com.unboundid.ldap.sdk.ExtendedRequest;
043    import com.unboundid.ldap.sdk.ExtendedResult;
044    import com.unboundid.ldap.sdk.Modification;
045    import com.unboundid.ldap.sdk.ModificationType;
046    import com.unboundid.util.NotMutable;
047    import com.unboundid.util.ThreadSafety;
048    import com.unboundid.util.ThreadSafetyLevel;
049    
050    import 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)
061    public 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    }