001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: AMIdentityRepository.java,v 1.21 2010/01/06 01:58:26 veiming Exp $ 026 * 027 * Portions Copyrighted 2011-2015 ForgeRock AS. 028 */ 029package com.sun.identity.idm; 030 031import java.util.ArrayList; 032import java.util.Collections; 033import java.util.HashMap; 034import java.util.HashSet; 035import java.util.Iterator; 036import java.util.Map; 037import java.util.Set; 038 039import javax.inject.Inject; 040import javax.security.auth.callback.Callback; 041 042import org.forgerock.openam.ldap.LDAPUtils; 043 044import com.google.inject.assistedinject.Assisted; 045import com.iplanet.am.sdk.AMHashMap; 046import com.iplanet.sso.SSOException; 047import com.iplanet.sso.SSOToken; 048import com.sun.identity.common.CaseInsensitiveHashMap; 049import com.sun.identity.common.DNUtils; 050import com.sun.identity.shared.debug.Debug; 051import com.sun.identity.sm.DNMapper; 052import com.sun.identity.sm.OrganizationConfigManager; 053import com.sun.identity.sm.SMSException; 054import org.forgerock.openam.utils.CrestQuery; 055 056/** 057 * The class <code> AMIdentityRepository </code> represents an object to access 058 * the repositories in which user/role/group and other identity data is 059 * configured. This class provides access to methods which will search, create 060 * and delete identities. An instance of this class can be obtained in the 061 * following manner: 062 * <p> 063 * 064 * <PRE> 065 * 066 * AMIdentityRepository idRepo = new AMIdentityRepository(ssoToken, realmName); 067 * 068 * </PRE> 069 * 070 * @supported.api 071 */ 072public final class AMIdentityRepository { 073 private SSOToken token; 074 private String organizationDN; 075 private String idRealmName; 076 077 public static Debug debug = Debug.getInstance("amIdm"); 078 public static Map listeners = new CaseInsensitiveHashMap(); 079 080 private static Set<IdRepoCreationListener> creationListeners = new HashSet<IdRepoCreationListener>(); 081 082 /** 083 * @supported.api 084 * 085 * Constructor for the <code>AMIdentityRepository</code> object. If a null 086 * is passed for the organization identifier <code>realmName</code>, then 087 * the "root" realm is assumed. 088 * 089 * @param ssotoken 090 * Single sign on token of the user 091 * @param realmName 092 * Name of the realm (can be a Fully qualified DN) 093 * @throws IdRepoException Never thrown, required by legacy code. 094 * @throws SSOException Never thrown, required by legacy code. 095 * @deprecated in 13.0.0, use {@link #AMIdentityRepository(String, com.iplanet.sso.SSOToken)} instead 096 */ 097 @Deprecated 098 public AMIdentityRepository(SSOToken ssotoken, String realmName) 099 throws IdRepoException, SSOException { 100 this(realmName, ssotoken); 101 } 102 103 /** 104 * @supported.api 105 * 106 * Constructor for the {@code AMIdentityRepository} object. If a {@code null} is passed for 107 * the organization identifier {@code realmName}, then the "root" realm is assumed. 108 * 109 * @param ssoToken Single sign on token of the user. 110 * @param realmName Name of the realm (can be a Fully qualified DN). 111 */ 112 @Inject 113 public AMIdentityRepository(@Assisted String realmName, @Assisted SSOToken ssoToken) { 114 token = ssoToken; 115 idRealmName = realmName; 116 organizationDN = DNMapper.orgNameToDN(realmName); 117 notifyCreationListeners(); 118 } 119 120 /** 121 * Adds a creation listener that will be notified each time a {@code AMIdentityRepository} is created . 122 * 123 * @param listener The listener. 124 */ 125 public static void addCreationListener(IdRepoCreationListener listener) { 126 creationListeners.add(listener); 127 } 128 129 /** 130 * Removes a creation listener so that it will no longer be notified when a 131 * {@code AMIdentityRepository} is created. 132 * 133 * @param listener The listener. 134 * @return {@code true} if the listener was removed. 135 */ 136 public static boolean removeCreationListener(IdRepoCreationListener listener) { 137 return creationListeners.remove(listener); 138 } 139 140 private void notifyCreationListeners() { 141 for (IdRepoCreationListener listener : creationListeners) { 142 listener.notify(this, idRealmName); 143 } 144 } 145 146 /** 147 * @supported.api 148 * 149 * Returns the set of supported object types <code>IdType</code> for this 150 * deployment. This is not realm specific. 151 * 152 * @return Set of supported <code> IdType </code> objects. 153 * @throws IdRepoException 154 * if there are repository related error conditions. 155 * @throws SSOException 156 * if user's single sign on token is invalid. 157 */ 158 public Set getSupportedIdTypes() throws IdRepoException, SSOException { 159 IdServices idServices = IdServicesFactory.getDataStoreServices(); 160 Set res = idServices.getSupportedTypes(token, organizationDN); 161 res.remove(IdType.REALM); 162 return res; 163 } 164 165 /** 166 * @supported.api 167 * 168 * Returns the set of Operations for a given <code>IdType</code>, 169 * <code>IdOperations</code> that can be performed on an Identity. This 170 * varies for each organization (and each plugin?). 171 * 172 * @param type 173 * Type of identity 174 * @return Set of <code>IdOperation</code> objects. 175 * @throws IdRepoException 176 * if there are repository related error conditions. 177 * @throws SSOException 178 * if user's single sign on token is invalid. 179 */ 180 public Set getAllowedIdOperations(IdType type) throws IdRepoException, 181 SSOException { 182 IdServices idServices = IdServicesFactory.getDataStoreServices(); 183 return idServices.getSupportedOperations(token, type, organizationDN); 184 } 185 186 /** 187 * 188 * Return the special identities for this realm for a given type. These 189 * identities cannot be deleted and hence have to be shown in the admin 190 * console as non-deletable. 191 * 192 * @param type 193 * Type of the identity 194 * @return IdSearchResult 195 * @throws IdRepoException 196 * if there is a datastore exception 197 * @throws SSOException 198 * if the user's single sign on token is not valid. 199 */ 200 public IdSearchResults getSpecialIdentities(IdType type) 201 throws IdRepoException, SSOException { 202 203 IdSearchResults results = getSpecialIdentities(token, type, 204 organizationDN); 205 206 if (type.equals(IdType.USER)) { 207 // Iterating through to get out the names and remove only amadmin 208 // anonymous as per AM console requirement. 209 210 IdSearchResults newResults = new IdSearchResults(type, 211 organizationDN); 212 Set identities = results.getSearchResults(); 213 if ((identities != null) && !identities.isEmpty()) { 214 for (Iterator i = identities.iterator(); i.hasNext();) { 215 AMIdentity amid = ((AMIdentity) i.next()); 216 String remUser = amid.getName().toLowerCase(); 217 if (!remUser.equalsIgnoreCase(IdConstants.AMADMIN_USER) 218 && !remUser.equalsIgnoreCase( 219 IdConstants.ANONYMOUS_USER)) 220 { 221 newResults.addResult(amid, Collections.EMPTY_MAP); 222 } 223 } 224 results = newResults; 225 } 226 } 227 return results; 228 } 229 230 /** 231 * Searches for identities of a certain type. The iterator returns 232 * AMIdentity objects for use by the application. 233 * 234 * @deprecated This method is deprecated. Use 235 * {@link #searchIdentities(IdType type,String pattern, 236 * IdSearchControl ctrl)} 237 * @param type 238 * Type of identity being searched for. 239 * @param pattern 240 * Search pattern, like "a*" or "*". 241 * @param avPairs 242 * Map of attribute-values which can further help qualify the 243 * search pattern. 244 * @param recursive 245 * If true, then the search is performed on the entire subtree 246 * (if applicable) 247 * @param maxResults 248 * Maximum number of results to be returned. A -1 means no limit 249 * on the result set. 250 * @param maxTime 251 * Maximum amount of time after which the search should return 252 * with partial results. 253 * @param returnAttributes 254 * Set of attributes to be read when performing the search. 255 * @param returnAllAttributes 256 * If true, then read all the attributes of the entries. 257 * @return results containing <code>AMIdentity</code> objects. 258 * @throws IdRepoException 259 * if there are repository related error conditions. 260 * @throws SSOException 261 * if user's single sign on token is invalid. 262 */ 263 public IdSearchResults searchIdentities(IdType type, String pattern, 264 Map avPairs, boolean recursive, int maxResults, int maxTime, 265 Set returnAttributes, boolean returnAllAttributes) 266 throws IdRepoException, SSOException { 267 268 IdSearchControl crtl = new IdSearchControl(); 269 crtl.setSearchModifiers(IdSearchOpModifier.OR, avPairs); 270 crtl.setRecursive(recursive); 271 crtl.setMaxResults(maxResults); 272 crtl.setTimeOut(maxTime); 273 crtl.setReturnAttributes(returnAttributes); 274 crtl.setAllReturnAttributes(returnAllAttributes); 275 276 // Call search method that takes IdSearchControl 277 CrestQuery crestQuery = new CrestQuery(pattern); 278 return searchIdentities(type, crestQuery, crtl); 279 } 280 281 /** 282 * @supported.api 283 * 284 * Searches for identities of certain types from each plugin and returns a 285 * combined result. 286 * 287 * <b>Note:</b> The AMIdentity objects representing IdType.REALM can be 288 * used for services related operations only. The realm <code>AMIdentity 289 * </code> object can be used to assign and unassign services containing 290 * dynamic attributes to this realm. 291 * 292 * @param type 293 * Type of identity being searched for. 294 * @param pattern 295 * Pattern to be used when searching. 296 * @param ctrl 297 * IdSearchControl which can be used to set up various search 298 * controls on the search to be performed. 299 * @return Returns the combined results in an object IdSearchResults. 300 * @see com.sun.identity.idm.IdSearchControl 301 * @see com.sun.identity.idm.IdSearchResults 302 * @throws IdRepoException 303 * if there are repository related error conditions. 304 * @throws SSOException 305 * if user's single sign on token is invalid. 306 */ 307 public IdSearchResults searchIdentities(IdType type, String pattern, IdSearchControl ctrl) 308 throws IdRepoException, SSOException { 309 310 CrestQuery crestQuery = new CrestQuery(pattern); 311 return searchIdentities(type, crestQuery, ctrl); 312 } 313 314 /** 315 * Searches for identities of certain types from each plugin and returns a 316 * combined result 317 * 318 * <b>Note:</b> The AMIdentity objects representing IdType.REALM can be 319 * used for services related operations only. The realm <code>AMIdentity 320 * </code> object can be used to assign and unassign services containing 321 * dynamic attributes to this realm. 322 * 323 * @param type 324 * Type of identity being searched for. 325 * @param crestQuery 326 * Basically just an object which supports both _queryId and _queryFilter 327 * @param ctrl 328 * IdSearchControl which can be used to set up various search 329 * controls on the search to be performed. 330 * @return Returns the combined results in an object IdSearchResults. 331 * @see com.sun.identity.idm.IdSearchControl 332 * @see com.sun.identity.idm.IdSearchResults 333 * @throws IdRepoException 334 * if there are repository related error conditions. 335 * @throws SSOException 336 * if user's single sign on token is invalid. 337 */ 338 public IdSearchResults searchIdentities(IdType type, CrestQuery crestQuery, IdSearchControl ctrl) 339 throws IdRepoException, SSOException { 340 341 IdSearchResults idSearchResults = null; 342 343 if (type.equals(IdType.REALM)) { 344 345 if (crestQuery.hasQueryFilter()) { 346 throw new IdRepoException("realm searchIdentities does not support query filters"); 347 } 348 349 try { 350 idSearchResults = new IdSearchResults(type, idRealmName); 351 OrganizationConfigManager orgMgr = 352 new OrganizationConfigManager(token, idRealmName); 353 354 // Realm searches only support _queryId 355 String pattern = crestQuery.getQueryId(); 356 357 Set realmNames = orgMgr.getSubOrganizationNames(pattern, false); 358 if (realmNames != null) { 359 Iterator iterator = realmNames.iterator(); 360 while (iterator.hasNext()) { 361 String realmName = (String) iterator.next(); 362 363 AMIdentity realmIdentity = getSubRealmIdentity(realmName); 364 Map attributes = new HashMap(); 365 366 idSearchResults.addResult(realmIdentity, attributes); 367 idSearchResults.setErrorCode(IdSearchResults.SUCCESS); 368 } 369 } 370 } catch (SMSException sme) { 371 debug.error("AMIdentityRepository.searchIdentities() - " 372 + "Error occurred while searching " + type.getName() 373 + ":", sme); 374 throw new IdRepoException(sme.getMessage()); 375 } 376 } else { 377 IdServices idServices = IdServicesFactory.getDataStoreServices(); 378 379 idSearchResults = idServices.search(token, type, ctrl, organizationDN, crestQuery); 380 } 381 return idSearchResults; 382 } 383 384 /** 385 * @supported.api 386 * 387 * Returns a handle of the Identity object representing this 388 * realm for services related operations only. This <code> AMIdentity 389 * </code> object can be used to assign and unassign services containing 390 * dynamic attributes to this realm 391 * 392 * @return a handle of the Identity object. 393 * @throws IdRepoException 394 * if there are repository related error conditions. 395 * @throws SSOException 396 * if user's single sign on token is invalid. 397 */ 398 public AMIdentity getRealmIdentity() throws IdRepoException, SSOException { 399 return getRealmIdentity(token, organizationDN); 400 } 401 402 private AMIdentity getRealmIdentity(SSOToken token, String orgDN) 403 throws IdRepoException { 404 String universalId = "id=ContainerDefaultTemplateRole,ou=realm," + 405 orgDN; 406 return IdUtils.getIdentity(token, universalId); 407 } 408 409 private AMIdentity getSubRealmIdentity(String subRealmName) throws 410 IdRepoException, SSOException { 411 String realmName = idRealmName; 412 if (LDAPUtils.isDN(idRealmName)) { // Wouldn't be a DN if it starts with "/" 413 realmName = DNMapper.orgNameToRealmName(idRealmName); 414 } 415 416 String fullRealmName = realmName + IdConstants.SLASH_SEPARATOR + 417 subRealmName; 418 String subOrganizationDN = DNMapper.orgNameToDN(fullRealmName); 419 420 return getRealmIdentity(token, subOrganizationDN); 421 } 422 423 /** 424 * @supported.api 425 * 426 * Creates a single object of a type. The object is 427 * created in all the plugins that support creation of this type of object. 428 * 429 * This method is only valid for: 430 * 431 * <ol> 432 * <li> {@link IdType#AGENT IdType.AGENT} </li> 433 * <li> {@link IdType#USER IdType.USER} </li> 434 * <li> {@link IdType#REALM IdType.REALM} </li> 435 * </ol> 436 * 437 * <br> 438 * <b>Note:</b> For creating {@link IdType#REALM IdType.REALM} identities, 439 * a map of <code>sunIdentityRepositoryService</code> attributes need to 440 * be passed. Also, AMIdentity object representing this realm can be 441 * used for services related operations only. This <code> AMIdentity 442 * </code> object can be used to assign and unassign services containing 443 * dynamic attributes to this realm 444 * 445 * 446 * @param type 447 * <code>IdType</code> of object to be created. 448 * @param idName 449 * Name of object. If the type is <code>IdType.REALM</code> 450 * then enter a valid realm name. 451 * @param attrMap 452 * Map of attribute-values to be set when creating the entry. 453 * @return Identity object representing the newly created entry. 454 * @throws IdRepoException 455 * if there are repository related error conditions. 456 * @throws SSOException 457 * if user's single sign on token is invalid. 458 */ 459 public AMIdentity createIdentity(IdType type, String idName, Map attrMap) 460 throws IdRepoException, SSOException { 461 IdServices idServices = IdServicesFactory.getDataStoreServices(); 462 return idServices.create(token, type, idName, attrMap, organizationDN); 463 } 464 465 /** 466 * @supported.api 467 * 468 * Creates multiple objects of the same type. The objects are created in all 469 * the <code>IdRepo</code> plugins that support creation of these objects. 470 * 471 * This method is only valid for: 472 * 473 * <ol> 474 * <li> {@link IdType#AGENT IdType.AGENT} </li> 475 * <li> (@link IdType#USER IdType.USER} </li> 476 * <li> {@link IdType#REALM IdType.REALM} </li> 477 * </ol> 478 * 479 * <br> 480 * <b>Note:</b> For creating {@link IdType#REALM IdType.REALM} identities, 481 * a map of <code>sunIdentityRepositoryService</code> attributes need to 482 * be passed. Also, AMIdentity object representing this realm can be 483 * used for services related operations only. This <code> AMIdentity 484 * </code> object can be used to assign and unassign services containing 485 * dynamic attributes to this realm. 486 * 487 * @param type 488 * Type of object to be created 489 * @param identityNamesAndAttrs 490 * Names of the identities and their 491 * @return Set of created Identities. 492 * @throws IdRepoException 493 * if there are repository related error conditions. 494 * @throws SSOException 495 * if user's single sign on token is invalid. 496 */ 497 public Set createIdentities(IdType type, Map identityNamesAndAttrs) 498 throws IdRepoException, SSOException { 499 Set results = new HashSet(); 500 501 if (identityNamesAndAttrs == null || identityNamesAndAttrs.isEmpty()) { 502 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.ILLEGAL_ARGUMENTS, null); 503 } 504 505 Iterator it = identityNamesAndAttrs.keySet().iterator(); 506 507 while (it.hasNext()) { 508 String name = (String) it.next(); 509 Map attrMap = (Map) identityNamesAndAttrs.get(name); 510 AMIdentity id = createIdentity(type, name, attrMap); 511 results.add(id); 512 } 513 514 return results; 515 } 516 517 /** 518 * @supported.api 519 * 520 * Deletes identities. The Set passed is a set of <code>AMIdentity</code> 521 * objects. 522 * 523 * This method is only valid for: 524 * <ol> 525 * <li> {@link IdType#AGENT IdType.AGENT} </li> 526 * <li> {@link IdType#REALM IdType.REALM} </li> 527 * <li> (@link IdType#USER IdType.USER} </li> 528 * </ol> 529 * 530 * @param type Type of Identity to be deleted. 531 * @param identities Set of <code>AMIdentity</code> objects to be deleted. 532 * @throws IdRepoException if there are repository related error conditions. 533 * @throws SSOException if user's single sign on token is invalid. 534 * @deprecated As of release AM 7.1, replaced by 535 * {@link #deleteIdentities(Set)} 536 */ 537 public void deleteIdentities(IdType type, Set identities) 538 throws IdRepoException, SSOException { 539 deleteIdentities(identities); 540 } 541 542 /** 543 * @supported.api 544 * 545 * Deletes identities. The Set passed is a set of <code>AMIdentity</code> 546 * objects. 547 * 548 * This method is only valid for: 549 * <ol> 550 * <li> {@link IdType#AGENT IdType.AGENT} </li> 551 * <li> {@link IdType#REALM IdType.REALM} </li> 552 * <li> (@link IdType#USER IdType.USER} </li> 553 * </ol> 554 * 555 * @param identities Set of <code>AMIdentity</code> objects to be deleted 556 * @throws IdRepoException if there are repository related error conditions. 557 * @throws SSOException if user's single sign on token is invalid. 558 */ 559 public void deleteIdentities(Set identities) throws IdRepoException, 560 SSOException { 561 if (identities == null || identities.isEmpty()) { 562 throw new IdRepoException(IdRepoBundle.BUNDLE_NAME, IdRepoErrorCode.ILLEGAL_ARGUMENTS, null); 563 } 564 565 Iterator it = identities.iterator(); 566 while (it.hasNext()) { 567 AMIdentity id = (AMIdentity) it.next(); 568 IdServices idServices = IdServicesFactory.getDataStoreServices(); 569 idServices.delete(token, id.getType(), id.getName(), organizationDN, 570 id.getDN()); 571 } 572 } 573 574 /** 575 * Non-javadoc, non-public methods Returns <code>true</code> if the data 576 * store has successfully authenticated the identity with the provided 577 * credentials. In case the data store requires additional credentials, the 578 * list would be returned via the <code>IdRepoException</code> exception. 579 * 580 * @param credentials 581 * Array of callback objects containing information such as 582 * username and password. 583 * 584 * @return <code>true</code> if data store authenticates the identity; 585 * else <code>false</code> 586 */ 587 public boolean authenticate(Callback[] credentials) throws IdRepoException, 588 com.sun.identity.authentication.spi.AuthLoginException { 589 IdServices idServices = IdServicesFactory.getDataStoreServices(); 590 return (idServices.authenticate(organizationDN, credentials)); 591 } 592 593 /** 594 * @supported.api 595 * 596 * Adds a listener, which should receive notifications for all changes that 597 * occurred in this organization. 598 * 599 * This method is only valid for IdType User and Agent. 600 * 601 * @param listener 602 * The callback which implements <code>AMEventListener</code>. 603 * @return Integer identifier for this listener. 604 */ 605 public int addEventListener(IdEventListener listener) { 606 ArrayList listOfListeners = (ArrayList) listeners.get(organizationDN); 607 if (listOfListeners == null) { 608 listOfListeners = new ArrayList(); 609 } 610 synchronized (listeners) { 611 listOfListeners.add(listener); 612 listeners.put(organizationDN, listOfListeners); 613 } 614 return (listOfListeners.size() - 1); 615 } 616 617 /** 618 * @supported.api 619 * 620 * Removes listener as the application is no longer interested in receiving 621 * notifications. 622 * 623 * @param identifier 624 * Integer identifying the listener. 625 */ 626 public void removeEventListener(int identifier) { 627 ArrayList listOfListeners = (ArrayList) listeners.get(organizationDN); 628 if (listOfListeners != null) { 629 synchronized (listeners) { 630 listOfListeners.remove(identifier); 631 } 632 } 633 } 634 635 /** 636 * @supported.api 637 * 638 * Clears the cache. 639 */ 640 public static void clearCache() { 641 IdServices idServices = IdServicesFactory.getDataStoreServices(); 642 idServices.reinitialize(); 643 IdUtils.initialize(); 644 } 645 646 647 public IdSearchResults getSpecialIdentities(SSOToken token, IdType type, 648 String orgName) throws IdRepoException, SSOException { 649 IdServices idServices = IdServicesFactory.getDataStoreServices(); 650 return idServices.getSpecialIdentities(token, type, orgName); 651 } 652 653 /** 654 * Return String representation of the <code>AMIdentityRepository 655 * </code> object. It returns realm name. 656 * 657 * @return String representation of <code>AMIdentityRepository</code> 658 * object. 659 */ 660 public String toString() { 661 StringBuilder sb = new StringBuilder(100); 662 sb.append("AMIdentityRepository object: ") 663 .append(organizationDN); 664 return (sb.toString()); 665 } 666 667 // TODO: 668 // FIXME: Move these utilities to a util class 669 private Map reverseMapAttributeNames(Map attrMap, Map configMap) { 670 if (attrMap == null || attrMap.isEmpty()) { 671 return attrMap; 672 } 673 Map resultMap; 674 Map[] mapArray = getAttributeNameMap(configMap); 675 if (mapArray == null) { 676 resultMap = attrMap; 677 } else { 678 resultMap = new CaseInsensitiveHashMap(); 679 Map reverseMap = mapArray[1]; 680 Iterator it = attrMap.keySet().iterator(); 681 while (it.hasNext()) { 682 String curr = (String) it.next(); 683 if (reverseMap.containsKey(curr)) { 684 resultMap.put((String) reverseMap.get(curr), (Set) attrMap 685 .get(curr)); 686 } else { 687 resultMap.put(curr, (Set) attrMap.get(curr)); 688 } 689 } 690 } 691 return resultMap; 692 } 693 694 private IdSearchResults combineSearchResults(SSOToken token, 695 Object[][] arrayOfResult, int sizeOfArray, IdType type, 696 String orgName, boolean amsdkIncluded, Object[][] amsdkResults) { 697 Map amsdkDNs = new CaseInsensitiveHashMap(); 698 Map resultsMap = new CaseInsensitiveHashMap(); 699 int errorCode = IdSearchResults.SUCCESS; 700 if (amsdkIncluded) { 701 RepoSearchResults amsdkRepoRes = (RepoSearchResults) 702 amsdkResults[0][0]; 703 Set results = amsdkRepoRes.getSearchResults(); 704 Map attrResults = amsdkRepoRes.getResultAttributes(); 705 for (String dn : (Set<String>) results) { 706 String name = LDAPUtils.rdnValueFromDn(dn); 707 amsdkDNs.put(name, dn); 708 Set attrMaps = new HashSet(); 709 attrMaps.add((Map) attrResults.get(dn)); 710 resultsMap.put(name, attrMaps); 711 } 712 errorCode = amsdkRepoRes.getErrorCode(); 713 } 714 for (int i = 0; i < sizeOfArray; i++) { 715 RepoSearchResults current = (RepoSearchResults) arrayOfResult[i][0]; 716 Map configMap = (Map) arrayOfResult[i][1]; 717 Map allAttrMaps = current.getResultAttributes(); 718 for (String m : (Set<String>) current.getSearchResults()) { 719 String mname = DNUtils.DNtoName(m); 720 Map attrMap = (Map) allAttrMaps.get(m); 721 attrMap = reverseMapAttributeNames(attrMap, configMap); 722 Set attrMaps = (Set) resultsMap.get(mname); 723 if (attrMaps == null) { 724 attrMaps = new HashSet(); 725 } 726 attrMaps.add(attrMap); 727 resultsMap.put(mname, attrMaps); 728 } 729 } 730 IdSearchResults results = new IdSearchResults(type, orgName); 731 for (String mname : (Set<String>) resultsMap.keySet()) { 732 Map combinedMap = combineAttrMaps((Set) resultsMap.get(mname), 733 true); 734 AMIdentity id = new AMIdentity(token, mname, type, orgName, 735 (String) amsdkDNs.get(mname)); 736 results.addResult(id, combinedMap); 737 } 738 results.setErrorCode(errorCode); 739 return results; 740 } 741 742 private Map[] getAttributeNameMap(Map configMap) { 743 Set attributeMap = (Set) configMap.get(IdConstants.ATTR_MAP); 744 745 if (attributeMap == null || attributeMap.isEmpty()) { 746 return null; 747 } else { 748 Map returnArray[] = new Map[2]; 749 int size = attributeMap.size(); 750 returnArray[0] = new CaseInsensitiveHashMap(size); 751 returnArray[1] = new CaseInsensitiveHashMap(size); 752 Iterator it = attributeMap.iterator(); 753 while (it.hasNext()) { 754 String mapString = (String) it.next(); 755 int eqIndex = mapString.indexOf('='); 756 if (eqIndex > -1) { 757 String first = mapString.substring(0, eqIndex); 758 String second = mapString.substring(eqIndex + 1); 759 returnArray[0].put(first, second); 760 returnArray[1].put(second, first); 761 } else { 762 returnArray[0].put(mapString, mapString); 763 returnArray[1].put(mapString, mapString); 764 } 765 } 766 return returnArray; 767 } 768 } 769 770 private Map combineAttrMaps(Set setOfMaps, boolean isString) { 771 // Map resultMap = new CaseInsensitiveHashMap(); 772 Map resultMap = new AMHashMap(); 773 Iterator it = setOfMaps.iterator(); 774 while (it.hasNext()) { 775 Map currMap = (Map) it.next(); 776 if (currMap != null) { 777 Iterator keyset = currMap.keySet().iterator(); 778 while (keyset.hasNext()) { 779 String thisAttr = (String) keyset.next(); 780 if (isString) { 781 Set resultSet = (Set) resultMap.get(thisAttr); 782 Set thisSet = (Set) currMap.get(thisAttr); 783 if (resultSet != null) { 784 resultSet.addAll(thisSet); 785 } else { 786 /* 787 * create a new Set so that we do not alter the set 788 * that is referenced in setOfMaps 789 */ 790 resultSet = new HashSet((Set) 791 currMap.get(thisAttr)); 792 resultMap.put(thisAttr, resultSet); 793 } 794 } else { // binary attributes 795 796 byte[][] resultSet = (byte[][]) resultMap.get(thisAttr); 797 byte[][] thisSet = (byte[][]) currMap.get(thisAttr); 798 int combinedSize = thisSet.length; 799 if (resultSet != null) { 800 combinedSize = resultSet.length + thisSet.length; 801 byte[][] tmpSet = new byte[combinedSize][]; 802 for (int i = 0; i < resultSet.length; i++) { 803 tmpSet[i] = (byte[]) resultSet[i]; 804 } 805 for (int i = 0; i < thisSet.length; i++) { 806 tmpSet[i] = (byte[]) thisSet[i]; 807 } 808 resultSet = tmpSet; 809 } else { 810 resultSet = (byte[][]) thisSet.clone(); 811 } 812 resultMap.put(thisAttr, resultSet); 813 814 } 815 816 } 817 } 818 } 819 return resultMap; 820 } 821}