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