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