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: PersistentObject.java,v 1.8 2009/07/02 20:27:01 hengming Exp $ 026 * 027 * Portions Copyrighted 2011-2015 ForgeRock AS. 028 */ 029 030package com.iplanet.ums; 031 032import com.iplanet.am.sdk.AMException; 033import com.iplanet.services.ldap.Attr; 034import com.iplanet.services.ldap.AttrSet; 035import com.iplanet.services.ldap.ModSet; 036import com.iplanet.services.ldap.aci.ACI; 037import com.iplanet.services.ldap.aci.ACIParseException; 038import com.iplanet.services.util.I18n; 039import com.iplanet.sso.SSOException; 040import com.iplanet.sso.SSOToken; 041import com.iplanet.sso.SSOTokenManager; 042import com.iplanet.ums.validation.Validation; 043import com.sun.identity.shared.debug.Debug; 044 045import java.io.Serializable; 046import java.security.Principal; 047import java.util.ArrayList; 048import java.util.Arrays; 049import java.util.Collection; 050import java.util.Collections; 051import java.util.HashSet; 052import java.util.Iterator; 053import java.util.Locale; 054 055import org.forgerock.openam.ldap.LDAPUtils; 056import org.forgerock.opendj.ldap.Attribute; 057import org.forgerock.opendj.ldap.ByteString; 058import org.forgerock.opendj.ldap.DN; 059import org.forgerock.opendj.ldap.Modification; 060import org.forgerock.opendj.ldap.ModificationType; 061import org.forgerock.opendj.ldap.RDN; 062import org.forgerock.opendj.ldap.SearchScope; 063 064/** 065 * Represents a persistent object in UMS. This is the base class for all objects 066 * that Object Management Module (OMM) manages in UMS. 067 * 068 * @supported.api 069 */ 070public class PersistentObject implements ISearch, Serializable, IUMSConstants { 071 072 public static final String COMPUTED_MEMBER_ATTR_NAME = "nsRole"; 073 074 private static Debug debug; 075 static { 076 debug = Debug.getInstance(IUMSConstants.UMS_DEBUG); 077 } 078 079 private static I18n i18n = I18n.getInstance(IUMSConstants.UMS_PKG); 080 081 /** 082 * Default Constructor 083 */ 084 protected PersistentObject() { 085 super(); 086 } 087 088 /** 089 * Constructor for PersistentObject given an authenticated session and guid, 090 * to instantiate from persistent storage. 091 * 092 * @param session 093 * Valid and authenticated session 094 * @param guid 095 * Globally unique identifier for the entity 096 * @throws UMSException 097 * for failure to find the object 098 * 099 */ 100 PersistentObject(Principal principal, Guid guid) throws UMSException { 101 String dn = guid.getDn(); 102 103 if (principal == null || dn == null) { 104 String msg; 105 if (principal == null) { 106 msg = i18n.getString(IUMSConstants.BAD_PRINCIPAL_HDL); 107 } else { 108 msg = i18n.getString(IUMSConstants.BAD_GUID); 109 } 110 111 throw new IllegalArgumentException(msg); 112 } 113 setGuid(guid); 114 setPrincipal(principal); 115 116 // If reading in the object turns out to be too expensive, comment 117 // out the read. The read method will throw an exception for 118 // an unfound object due to access rights or bad guid. 119 // TODO: to be reviewed if we need to comment out this 120 // 121 read(); 122 } 123 124 /** 125 * Constructor for in memory object to be added to the system. You can make 126 * the object persistent two ways: 127 * <P> 128 * 129 * 1) call add on parent object (recommended) 130 * <P> 131 * 2) call save(...) method after all attributes for in memory object are 132 * set up properly. 133 * <P> 134 * 135 * @param template 136 * Object creation template. The template holds all the default 137 * values such as objectclass and requirted attributes to be 138 * supplied 139 * @param attrSet 140 * Attribute set to construct the object in memory 141 * @throws UMSException 142 * for failure to construct the object. The given attrSet needs 143 * to provide the required attribute(s) defined in template 144 * 145 * @supported.api 146 */ 147 public PersistentObject(CreationTemplate template, AttrSet attrSet) 148 throws UMSException { 149 m_attrSet = attrSet; 150 if (template == null) { 151 throw new UMSException(BAD_TEMPLATE); 152 } 153 m_namingAttribute = template.getNamingAttribute(); 154 template.validateAttrSet(attrSet); 155 template.validateAttributes(attrSet); 156 } 157 158 /** 159 * Constructor for in memory object to be added to the system. You can make 160 * the object persistent two ways: 161 * <P> 162 * 163 * 1) call add on parent object (recommended) 164 * <P> 165 * 2) call save(...) method after all attributes for in memory object are 166 * set up properly. 167 * <P> 168 * 169 * @param template 170 * Object creation template. The template holds all the default 171 * values such as objectclass and requirted attributes to be 172 * supplied 173 * @param attrSet 174 * Attribute set to construct the object in memory 175 * @param namingAttribute 176 * Internal naming attribute (ex: "ou"). 177 * @throws UMSException 178 * for failure to construct the object. The given attrSet needs 179 * to provide the required attribute(s) defined in template 180 */ 181 PersistentObject(CreationTemplate template, AttrSet attrSet, 182 String namingAttribute) throws UMSException { 183 184 m_attrSet = attrSet; 185 if (template == null) { 186 throw new UMSException(BAD_TEMPLATE); 187 } 188 template.validateAttrSet(attrSet); 189 template.validateAttributes(attrSet); 190 m_namingAttribute = namingAttribute; 191 } 192 193 /** 194 * Gets an attribute of the object. If the attribute is not in memory, the 195 * object is refreshed from persistent storage. 196 * 197 * @param attrName 198 * Name of the attribute to be queried 199 * @return Attribute value 200 * 201 * @supported.api 202 */ 203 public Attr getAttribute(String attrName) { 204 Attr attr = getAttributeFromCache(attrName); 205 if ((attr == null) && isAttributeNotRead(attrName) 206 && (getGuid() != null) && (getPrincipal() != null)) { 207 try { 208 attr = readAttributeFromDataStore(attrName); 209 } catch (UMSException ex) { 210 if (debug.warningEnabled()) { 211 debug.warning("PersistentObject.getAttribute: for DN: " + 212 getGuid() + " attribute: " + attrName, ex); 213 } 214 } 215 } 216 return attr; 217 } 218 219 /** 220 * Gets an attribute value with a given locale 221 * 222 * @param attrName 223 * Name of the attribute 224 * @param locale 225 * Locale of attribute to be retrieved 226 * @return Attribute value with the specified locale. May return null if the 227 * attribute with locale not found. No fallback mechanism is 228 * provided 229 * @see com.iplanet.ums.PersistentObject#getAttribute(String) 230 * 231 * @supported.api 232 */ 233 public Attr getAttribute(String attrName, Locale locale) 234 throws UMSException { 235 236 if (locale == null) { 237 return getAttribute(attrName); 238 } 239 240 return getAttribute(Attr.getName(attrName, locale)); 241 } 242 243 /** 244 * Gets attribute values 245 * 246 * @param attrs 247 * Array of strings representing attribute names 248 * @return attribute value set for the return values 249 * @see #getAttribute(String) 250 * 251 * @supported.api 252 */ 253 public AttrSet getAttributes(String[] attrs) throws UMSException { 254 return getAttributes(attrs, false); 255 } 256 257 /** 258 * Gets attribute values 259 * 260 * @param attrs 261 * Array of strings representing attribute names 262 * @param cacheOnly 263 * if true, read attributes from cache only without contacting 264 * data stroe 265 * @return attribute value set for the return values 266 * @see #getAttribute(String) 267 * 268 * @supported.api 269 */ 270 public AttrSet getAttributes(String[] attrs, boolean cacheOnly) 271 throws UMSException { 272 if (attrs == null) { 273 throw new IllegalArgumentException(i18n 274 .getString(IUMSConstants.BAD_ATTRNAMES)); 275 } 276 AttrSet attrSet = new AttrSet(); 277 if (!cacheOnly) { 278 Collection attributesNotInCache = findAttributesNotRead(attrs); 279 if ((!attributesNotInCache.isEmpty()) && (getGuid() != null) 280 && (getPrincipal() != null)) { 281 readAttributesFromDataStore(attributesNotInCache); 282 } 283 } 284 int length = attrs.length; 285 for (int i = 0; i < length; i++) { 286 Attr attr = getAttributeFromCache(attrs[i]); 287 if (attr != null) { 288 attrSet.add(attr); 289 } 290 } 291 return attrSet; 292 } 293 294 /** 295 * Returns attribute values with a specified locale. 296 * 297 * @param attrNames Attribute names 298 * @param locale Locale of the attributes to be queried 299 * @return Attribute value set. May return null value for attribute(s) with 300 * unfound locale. No fallback mechanism is provided. 301 * @see #getAttribute(String) 302 * 303 * @supported.api 304 */ 305 public AttrSet getAttributes(String attrNames[], Locale locale) 306 throws UMSException { 307 if (locale == null) 308 return getAttributes(attrNames); 309 310 String[] namesWithLocale = new String[attrNames.length]; 311 312 for (int i = 0; i < attrNames.length; i++) { 313 namesWithLocale[i] = Attr.getName(attrNames[i], locale); 314 } 315 316 return getAttributes(namesWithLocale); 317 } 318 319 /** 320 * Set an attribute value for the entity. 321 * <P> 322 * IMPORTANT: To make the changes persistent, you need to call the save 323 * method to save the changes. 324 * <P> 325 * 326 * @param attr 327 * Attribute and value 328 * 329 * @supported.api 330 */ 331 public void setAttribute(Attr attr) { 332 333 if (attr == null || (attr.getName() == null)) { 334 throw new IllegalArgumentException(i18n 335 .getString(IUMSConstants.ADD_NULL_OBJ)); 336 } 337 338 checkCache(); 339 340 if (m_attrSet == null) 341 m_attrSet = new AttrSet(); 342 343 if (m_attrSet.contains(attr.getName())) { 344 modify(attr, ModificationType.REPLACE); 345 } else { 346 modify(attr, ModificationType.ADD); 347 } 348 } 349 350 /** 351 * Sets an attribute value with a given locale for the entity. 352 * <P> 353 * IMPORTANT: To make the changes persistent, you need to call the save 354 * method to save the changes. 355 * <P> 356 * 357 * @param attr 358 * Attribute and value 359 * @param locale 360 * Intended locale of the attribute to be set 361 * 362 * @supported.api 363 */ 364 public void setAttribute(Attr attr, Locale locale) { 365 366 if (locale == null) { 367 setAttribute(attr); 368 return; 369 } 370 371 // TODO: ??? should check if adding Attr.setName method makes more 372 // sense than recopying the data values of the passed in attribute 373 // 374 Attr attrWithLocale = new Attr( 375 Attr.getName(attr.getBaseName(), locale)); 376 attrWithLocale.addValues(attr.getStringValues()); 377 setAttribute(attrWithLocale); 378 } 379 380 /** 381 * Changes user password. 382 * 383 * @param entryDN DN of the profile whose template is to be set 384 * @param attrName password attribute name 385 * @param oldPassword old password 386 * @param newPassword new password 387 * @throws AMException if an error occurs when changing user password 388 * @throws SSOException If user's single sign on token is invalid. 389 */ 390 public void changePassword(String entryDN, String attrName, 391 String oldPassword, String newPassword) throws UMSException { 392 393 DataLayer.getInstance().changePassword(getGuid(), attrName, 394 oldPassword, newPassword); 395 } 396 397 /** 398 * Removes attribute value for the entity. 399 * <P> 400 * IMPORTANT: To make the changes persistent, you need to call the save 401 * method to save the changes. 402 * <P> 403 * 404 * @param attr 405 * Attribute to be removed 406 * 407 * @supported.api 408 */ 409 public void removeAttribute(Attr attr) { 410 checkCache(); 411 if (m_attrSet == null || m_attrSet.size() == 0) { 412 return; 413 } 414 415 modify(attr, ModificationType.DELETE); 416 } 417 418 /** 419 * Gets names for all available attributes for this entity 420 * 421 * @return Array of strings representing attribute names 422 * 423 * @supported.api 424 */ 425 public String[] getAttributeNames() { 426 if (m_principal != null && m_guid != null && m_attrSet == null) { 427 try { 428 read(); 429 } catch (UMSException e) { 430 // TODO log exception here. 431 if (debug.messageEnabled()) { 432 debug.message("PersistentObject.getAttributeNames: " + 433 "UMSException: " + e.getMessage()); 434 } 435 } 436 } 437 438 if (m_attrSet != null) { 439 return m_attrSet.getAttributeNames(); 440 } else { 441 return null; 442 } 443 } 444 445 /** 446 * Modifies attribute values for the entity. 447 * <P> 448 * IMPORTANT: To make the changes persistent, you need to call the save 449 * method to save the changes. 450 * <P> 451 * 452 * @param modSet 453 * Set of modification of attributes 454 * @see ModSet 455 * 456 * @supported.api 457 */ 458 public void modify(Collection<Modification> modSet) { 459 checkCache(); 460 if (m_modSet == null) { 461 m_modSet = new HashSet<>(); 462 } 463 if (m_attrSet == null) { 464 m_attrSet = new AttrSet(); 465 } 466 467 for (Modification mod : modSet) { 468 switch (mod.getModificationType().intValue()) { 469 case 0://ModSet.ADD: 470 m_attrSet.add(new Attr(mod.getAttribute())); 471 break; 472 case 1://ModSet.DELETE: 473 if (mod.getAttribute().size() == 0) { 474 m_attrSet.remove(mod.getAttribute().getAttributeDescriptionAsString()); 475 } else { 476 Attribute attr = mod.getAttribute(); 477 for (ByteString value : attr) { 478 m_attrSet.remove(attr.getAttributeDescriptionAsString(), value.toString()); 479 } 480 } 481 break; 482 case 2://ModSet.REPLACE: 483 m_attrSet.replace(new Attr(mod.getAttribute())); 484 break; 485 default: 486 break; 487 } 488 489 m_modSet.add(mod); 490 491 } 492 } 493 494 /** 495 * Modifies the values of a single attribute for the entity. 496 * <P> 497 * IMPORTANT: To make the changes persistent, you need to call the save 498 * method to save the changes. 499 * <P> 500 * 501 * @param attr 502 * Attribute value to be modified 503 * @param modificationType 504 * Operation type in the modification. Input values include 505 * 506 * <pre> 507 * ModificationType.ADD, 508 * ModificationType.DELETE, 509 * ModificationType.REPLACE, 510 * ModificationType.INCREMENT 511 * </pre> 512 * 513 * @see ModSet 514 * 515 * @supported.api 516 */ 517 public void modify(Attr attr, ModificationType modificationType) { 518 Modification modification = new Modification(modificationType, attr.toLDAPAttribute()); 519 modify(Collections.singleton(modification)); 520 } 521 522 /** 523 * Modify a single attribute for the entity. 524 * <P> 525 * IMPORTANT: To make the changes persistent, you need to call the save 526 * method to save the changes. 527 * <P> 528 * 529 * @param attrName 530 * Attribute name of the attribute to be modified 531 * @param value 532 * String value of the attribute 533 * @param modificationType 534 * Operation type in the modification. Input values include 535 * 536 * <pre> 537 * ModificationType.ADD, 538 * ModificationType.DELETE, 539 * ModificationType.REPLACE, 540 * ModificationType.INCREMENT 541 * </pre> 542 * 543 * @supported.api 544 */ 545 public void modify(String attrName, String value, ModificationType modificationType) { 546 modify(new Attr(attrName, value), modificationType); 547 } 548 549 /** 550 * Get GUID of the given entity 551 * 552 * @return the GUID. 553 * 554 * @supported.api 555 */ 556 public Guid getGuid() { 557 return m_guid; 558 } 559 560 /** 561 * Renames the RDN to a new value. Note: The modified or added attribute 562 * values are not saved by this call. 563 * 564 * @param newRDN 565 * the new RDN value 566 * @param deleteOldName 567 * if true old RDN value is deleted, otherwise the old value is 568 * retained. 569 * 570 * @throws AccessRightsException 571 * if an access rights exception occurs. 572 * @throws EntryNotFoundException 573 * if the entry is not found 574 * @throws UMSException 575 * on failure to save to persistent storage 576 * 577 * @supported.api 578 */ 579 public void rename(String newRDN, boolean deleteOldName) 580 throws AccessRightsException, EntryNotFoundException, UMSException { 581 String required = null; 582 583 if (m_principal == null) { 584 required = "principal"; 585 } else if (m_guid == null) { 586 required = "guid"; 587 } 588 if (required != null) { 589 // TODO: This is not an illegal argument case. Should be 590 // a more sophisticated exception. 591 String args[] = new String[1]; 592 593 args[0] = required; 594 String msg = i18n.getString(IUMSConstants.NO_REQUIRED, args); 595 throw new UMSException(msg); 596 } 597 598 try { 599 DataLayer.getInstance().rename(getPrincipal(), getGuid(), newRDN, 600 deleteOldName); 601 } finally { 602 // Must be set to new ID since the orignal DN would have changed now 603 RDN rdn = RDN.valueOf(newRDN); 604 DN parentDN = DN.valueOf(m_guid.toString()).parent(); 605 parentDN.child(rdn); 606 m_guid.setDn(parentDN.toString()); 607 } 608 } 609 610 /** 611 * Save the modification(s) to the object. Save the changes made so far for 612 * the persistent object. In other words, make the changes persistent for 613 * the object. 614 * <P> 615 * This save method takes no parameter. You use this save method when the 616 * object is already instantiated. For example, 617 * 618 * <pre> 619 * User user = (User) UMSObject.getObject(principal, id); 620 * user.modify("telephonenumber", 621 * "650.937.4444", ModificationType.REPLACE); 622 * user.save(); 623 * </pre> 624 * 625 * <P> 626 * 627 * @throws AccessRightsException 628 * if an access rights exception occurs. 629 * @throws EntryNotFoundException 630 * if the entry is not found 631 * @throws UMSException 632 * on failure to save to persistent storage 633 * 634 * @supported.api 635 */ 636 public void save() throws AccessRightsException, EntryNotFoundException, 637 UMSException { 638 String required = null; 639 if (m_modSet == null) { 640 return; 641 } 642 if (m_principal == null) { 643 required = "principal"; 644 } else if (m_guid == null) { 645 required = "guid"; 646 } 647 if (required != null) { 648 // TODO: This is not an illegal argument case. Should be 649 // a more sophisticated exception. 650 String args[] = new String[1]; 651 652 args[0] = required; 653 String msg = i18n.getString(IUMSConstants.NO_REQUIRED, args) 654 + " - " 655 + i18n.getString(IUMSConstants.OBJECT_NOT_PERSISTENT); 656 throw new UMSException(msg); 657 } 658 659 try { 660 DataLayer.getInstance().modify(getPrincipal(), getGuid(), m_modSet); 661 } finally { 662 // Remember to set this to null as the changes 663 // are made persistent after this call 664 m_modSet = null; 665 } 666 } 667 668 /** 669 * Gets the attribute name that specifies the ID (or RDN in terms of DN in 670 * ldap) component in an object. Subclasses may choose to override this 671 * function. For instance, User takes either "uid" or "cn" for its 672 * identification 673 * <P> 674 * 675 * @return Attribute name for identification 676 * 677 * @supported.api 678 */ 679 public String getNamingAttribute() { 680 681 if (m_guid == null) { 682 return m_namingAttribute; 683 } 684 685 DN dn = DN.valueOf(getDN()); 686 if (dn.size() > 0) { 687 return LDAPUtils.rdnTypeFromDn(dn); 688 } 689 return null; 690 } 691 692 /** 693 * Gets the parent object 694 * 695 * @return PersistentObject representing the parent object 696 * @throws UMSException 697 * on failure instantiating the parent object 698 * 699 * @supported.api 700 */ 701 public PersistentObject getParentObject() throws UMSException { 702 703 if (m_guid == null || m_principal == null) { 704 String msg; 705 706 if (m_principal == null) { 707 msg = i18n.getString(IUMSConstants.BAD_PRINCIPAL_HDL); 708 } else { 709 msg = i18n.getString(IUMSConstants.BAD_GUID); 710 } 711 712 throw new IllegalArgumentException(msg); 713 } 714 715 PersistentObject parent = UMSObject.getObject(getPrincipal(), 716 getParentGuid()); 717 return parent; 718 } 719 720 /** 721 * Adds a child object to the persistent object container. All persistent 722 * objects can add objects as a container. To override this behavior or 723 * impose restrictions override the add method in a subclass so that e.g. 724 * User.add( object ) is restricted or disallowed in certain ways. 725 * 726 * @param object Child object to be added to this persistent container. 727 * @throws AccessRightsException if an access rights exception occurs. 728 * @throws EntryAlreadyExistsException if the entry already exists. 729 * @throws UMSException if fail to add the given child object to the 730 * container. Possible causes include 731 * <code>EntryAlreadyExists</code>, <code>AccessRights</code> 732 * violation. 733 * 734 * @supported.api 735 */ 736 public void addChild(PersistentObject object) throws AccessRightsException, 737 EntryAlreadyExistsException, UMSException { 738 if (object == null) { 739 String args[] = new String[1]; 740 741 args[0] = this.toString(); 742 String msg = i18n.getString(IUMSConstants.ADD_NULL_OBJ, args); 743 744 throw new IllegalArgumentException(msg); 745 } 746 747 String idAttr = object.getNamingAttribute(); 748 String idValue = null; 749 Attr idAttrObj = object.getAttribute(idAttr); 750 if (idAttrObj != null) { 751 idValue = idAttrObj.getValue(); 752 } else { 753 throw new UMSException(BAD_NAMING_ATTR + idAttr); 754 } 755 756 if (idAttr == null || idValue == null || idValue.length() == 0) { 757 String args[] = new String[1]; 758 759 args[0] = object.toString(); 760 String msg = i18n 761 .getString(IUMSConstants.COMPOSE_GUID_FAILED, args); 762 763 throw new IllegalArgumentException(msg); 764 } 765 766 String childStr = null; 767 768 if (getGuid().getDn().length() > 0) { 769 childStr = idAttr + "=" + idValue + "," + getGuid().getDn(); 770 } else { 771 childStr = idAttr + "=" + idValue; 772 } 773 774 Guid childGuid = new Guid(childStr); 775 object.setGuid(childGuid); 776 777 // Validation was done during the creation of the object 778 // Validation.validateAttributes( object.getAttrSet(), 779 // object.getClass(), this.getGUID() ); 780 781 DataLayer.getInstance().addEntry(getPrincipal(), childGuid, 782 object.getAttrSet()); 783 784 object.setModSet(null); 785 object.setPrincipal(getPrincipal()); 786 787 EntityManager em = EntityManager.getEntityManager(); 788 try { 789 em.execute(getPrincipal(), object, m_guid); 790 } catch (UMSException e) { 791 // TODO - we should log error... 792 if (debug.messageEnabled()) { 793 debug.message("PersistentObject.addChild : UMSException : " 794 + e.getMessage()); 795 } 796 } 797 } 798 799 /** 800 * Removes a child object from a persistent object container. It is 801 * important for constraints to be applied in overriding this method in 802 * subclasses of PersistentObject. For example, Organization may choose not 803 * to allow remove( object ) when object is an organization. 804 * 805 * @param object Child object to be removed. 806 * @throws AccessRightsException if an access rights exception occurs. 807 * @throws EntryNotFoundException if the entry is not found. 808 * @throws UMSException if fail to remove the child object. Possible causes 809 * includes EntryNotFount, AccessRights violation etc. 810 * 811 * @supported.api 812 */ 813 public void removeChild(PersistentObject object) 814 throws AccessRightsException, EntryNotFoundException, UMSException { 815 String childStr; 816 if (object == null) { 817 String args[] = new String[1]; 818 819 args[0] = this.toString(); 820 String msg = i18n.getString(IUMSConstants.DEL_NULL_OBJ, args); 821 throw new IllegalArgumentException(msg); 822 } 823 824 childStr = object.getGuid().getDn(); 825 826 // If this is an in-memory object, attempt to compose the guid 827 // for the child object 828 // 829 if (childStr == null) { 830 String idAttr = object.getNamingAttribute(); 831 String idValue = object.getAttribute(idAttr).getValue(); 832 833 if (idAttr == null || idValue == null || idValue.length() == 0) { 834 String args[] = new String[1]; 835 836 args[0] = object.toString(); 837 String msg = i18n.getString(IUMSConstants.COMPOSE_GUID_FAILED, 838 args); 839 840 throw new IllegalArgumentException(msg); 841 } 842 843 if (getGuid().getDn().length() > 0) { 844 childStr = idAttr + "=" + idValue + "," + getGuid(); 845 } else { 846 childStr = idAttr + "=" + idValue; 847 } 848 } 849 850 DN parentEntry = DN.valueOf(getDN()); 851 DN childEntry = DN.valueOf(childStr); 852 853 if (!childEntry.isInScopeOf(parentEntry, SearchScope.SUBORDINATES)) { 854 String msg = i18n.getString(IUMSConstants.BAD_CHILD_OBJ); 855 // TODO: need review. Should we throw something 856 // more meaningful 857 throw new IllegalArgumentException(msg); 858 } 859 860 DataLayer.getInstance().deleteEntry(getPrincipal(), new Guid(childStr)); 861 862 // TODO: ??? do we need to mark the object that has been deleted 863 // with an invalid session 864 // 865 object.setGuid(new Guid("DELETED")); 866 object.setPrincipal(null); 867 } 868 869 /** 870 * Removes an object given its unique ID. This method expects the given 871 * child ID is a descendant (something being contained) in "this" object 872 * 873 * @param childGuid Unique entry identification for the child to be removed. 874 * @throws AccessRights if an access rights exception occurs. 875 * @throws EntryNotFoundException if the entry is not found. 876 * @throws UMSException if failure to remove the entry from the persistent 877 * store. Possible causes include AccessRights violation, 878 * EntryNotFound etc. 879 * 880 * @supported.api 881 */ 882 public void removeChild(Guid childGuid) throws AccessRightsException, 883 EntryNotFoundException, UMSException { 884 DN parentEntry = DN.valueOf(getDN()); 885 DN childEntry = DN.valueOf(childGuid.getDn()); 886 887 if (!childEntry.isInScopeOf(parentEntry, SearchScope.SUBORDINATES)) { 888 String msg = i18n.getString(IUMSConstants.BAD_CHILD_OBJ); 889 890 throw new IllegalArgumentException(msg); 891 } 892 893 DataLayer.getInstance().deleteEntry(getPrincipal(), childGuid); 894 } 895 896 /** 897 * Remove itself from the persistent store. This method removes the object 898 * at hand from the persistent storage but keeps its internal data so that 899 * the ums client can save it to somewhere else or make reference to its 900 * internal data 901 * <P> 902 * 903 * @throws AccessRights 904 * Exception if an access rights exception occurs. 905 * @throws EntryNotFoundException 906 * if the entry is not found 907 * @throws UMSException 908 * from UMSSession.removeObject( principal, guid) 909 * 910 * @supported.api 911 */ 912 public void remove() throws AccessRightsException, EntryNotFoundException, 913 UMSException { 914 // REVIEW: should we keep this method where an object can delete itself 915 // we don't allow an object to add itself ^%$#@ 916 917 // If this is an in memory object with no reference to an entry, 918 // don't do anything 919 // 920 if (m_guid == null || m_principal == null) 921 return; 922 923 // Remove the object from persitent store 924 // 925 DataLayer.getInstance().deleteEntry(getPrincipal(), getGuid()); 926 927 // Now reset it as a memory object with no reference to an entry on 928 // the persistent store. Possible use of this object in a move 929 // implementation. Call save(principal, namingAttr, parentGUID) to 930 // achieve 931 // the more functionality 932 // 933 setGuid(null); 934 setPrincipal(null); 935 } 936 937 /** 938 * Gets a string representation of the object 939 * 940 * @return String representation of the object 941 * 942 * @supported.api 943 */ 944 public String toString() { 945 StringBuilder sb = new StringBuilder(); 946 sb.append("Object ID :").append(m_guid).append("\n"); 947 sb.append("Naming attribute :").append(getNamingAttribute()).append("\n"); 948 sb.append("Class :").append(getClass().getName()).append("\n"); 949 sb.append("Principal :").append(m_principal).append("\n"); 950 sb.append("Attribute Set :").append(m_attrSet).append("\n"); 951 return sb.toString(); 952 } 953 954 /** 955 * Gets the parent guid 956 * 957 * @return string representation of the parent guid public String 958 * getParentID() { return getParentID(null); } 959 */ 960 961 /** 962 * Gets the parent guid 963 * 964 * @return String representation of the parent guid 965 */ 966 public Guid getParentGuid() { 967 if (m_guid == null || m_principal == null) { 968 return null; 969 } 970 971 DN dn = DN.valueOf(getDN()); 972 return new Guid(dn.parent().toString()); 973 } 974 975 /** 976 * Gets the immediate children, subject to search filter constraints. Only 977 * the IDs and object classes of each child are returned. 978 * <P> 979 * 980 * @param filter 981 * Search filter 982 * @param searchControl 983 * Search control 984 * @return Result child IDs in Vector 985 * @throws InvalidSearchFilterException 986 * if the search filter is invalid 987 * @throws UMSException 988 * on searching for immediate children in the container 989 * 990 * @supported.api 991 */ 992 public SearchResults getChildren(String filter, SearchControl searchControl) 993 throws InvalidSearchFilterException, UMSException { 994 // default is one level search scope in getChildren 995 // 996 int scope = SearchControl.SCOPE_ONE; 997 if (searchControl != null) { 998 scope = searchControl.getSearchScope(scope); 999 } 1000 1001 SearchResults results = DataLayer.getInstance().searchIDs( 1002 getPrincipal(), getGuid(), scope, filter, searchControl); 1003 results.setPrincipal(getPrincipal()); 1004 return results; 1005 } 1006 1007 /** 1008 * Gets the immediate children, returning only specified attributes 1009 * 1010 * @param filter 1011 * Search filter 1012 * @param resultAttributeNames 1013 * Names of attributes to retrieve 1014 * @param searchControl 1015 * Search control object 1016 * @return SearchResults 1017 * @throws InvalidSearchFilterException 1018 * on invalid search filter 1019 * @throws UMSException 1020 * on failure with searhing 1021 * 1022 * @supported.api 1023 */ 1024 public SearchResults getChildren(String filter, 1025 String[] resultAttributeNames, SearchControl searchControl) 1026 throws InvalidSearchFilterException, UMSException { 1027 1028 // default is one level search scope in getChildren 1029 // 1030 int scope = SearchControl.SCOPE_ONE; 1031 if (searchControl != null) { 1032 scope = searchControl.getSearchScope(scope); 1033 } 1034 1035 SearchResults searchResults = DataLayer.getInstance().search( 1036 getPrincipal(), getGuid(), scope, filter, resultAttributeNames, 1037 false, searchControl); 1038 searchResults.setPrincipal(getPrincipal()); 1039 1040 return searchResults; 1041 } 1042 1043 /** 1044 * Gets all immediate children under current node based on search criteria 1045 * specified in template, and returns attributes specified there. Search 1046 * behavior is controlled by searchControl. 1047 * <P> 1048 * 1049 * Returning attributes are determined by the search template 1050 * <P> 1051 * 1052 * @param template 1053 * Search template 1054 * @param searchControl 1055 * Search control, use default setting if searchControl == null 1056 * @throws UMSException 1057 * on failure with searching 1058 * 1059 * @supported.api 1060 */ 1061 public SearchResults getChildren(SearchTemplate template, 1062 SearchControl searchControl) throws UMSException { 1063 return getChildren(template.getSearchFilter(), template 1064 .getAttributeSet().getAttributeNames(), searchControl); 1065 } 1066 1067 /** 1068 * Gets only the IDs and object classes of all objects at the current level 1069 * and below which match the search filter. 1070 * 1071 * @param filter 1072 * Search filter 1073 * @param searchControl 1074 * Search control object 1075 * @throws InvalidSearchFilterException 1076 * on invalid search filter 1077 * @throws UMSException 1078 * on failure with searching 1079 * 1080 * @supported.api 1081 */ 1082 public SearchResults search(String filter, SearchControl searchControl) 1083 throws InvalidSearchFilterException, UMSException { 1084 1085 // Default search scope is Subtree type of search 1086 // 1087 int scope = SearchControl.SCOPE_SUB; 1088 if (searchControl != null) { 1089 scope = searchControl.getSearchScope(scope); 1090 } 1091 1092 SearchResults results = DataLayer.getInstance().searchIDs( 1093 getPrincipal(), getGuid(), scope, filter, searchControl); 1094 results.setPrincipal(getPrincipal()); 1095 return results; 1096 } 1097 1098 /** 1099 * Gets the specified attributes of all objects at the current level and 1100 * below which match the search filter. 1101 * 1102 * @param filter 1103 * Search filter 1104 * @param resultAttributeNames 1105 * Names of attributes to retrieve 1106 * @param searchControl 1107 * Search control object 1108 * @return SearchResults 1109 * @throws InvalidSearchFilterException 1110 * on invalid search filter 1111 * @throws UMSException 1112 * on failure with searching 1113 * 1114 * 1115 * @supported.api 1116 */ 1117 public SearchResults search(String filter, String[] resultAttributeNames, 1118 SearchControl searchControl) throws InvalidSearchFilterException, 1119 UMSException { 1120 1121 // Default search scope is Subtree type of search 1122 // 1123 int scope = SearchControl.SCOPE_SUB; 1124 if (searchControl != null) { 1125 scope = searchControl.getSearchScope(scope); 1126 } 1127 1128 SearchResults results = DataLayer.getInstance().search(getPrincipal(), 1129 getGuid(), scope, filter, resultAttributeNames, false, 1130 searchControl); 1131 results.setPrincipal(getPrincipal()); 1132 return results; 1133 } 1134 1135 /** 1136 * Gets the attributes specified in the template for all objects at the 1137 * current level and below which match the search filter in the template. 1138 * Search behavior is controlled by searchControl. 1139 * <P> 1140 * 1141 * @param template 1142 * Search template 1143 * @param searchControl 1144 * Search control, use default setting if searchControl == null 1145 * @throws UMSException 1146 * on failure to search 1147 * 1148 * @supported.api 1149 */ 1150 public SearchResults search(SearchTemplate template, 1151 SearchControl searchControl) throws UMSException { 1152 return search(template.getSearchFilter(), template.getAttributeSet() 1153 .getAttributeNames(), searchControl); 1154 } 1155 1156 /** 1157 * Gets the DN of the entity 1158 * 1159 * @return String representing the distinguished name of the entry 1160 * 1161 */ 1162 public String getDN() { 1163 if (m_guid != null) 1164 return m_guid.getDn(); 1165 else 1166 return null; 1167 } 1168 1169 /** 1170 * Sets the GUID of the entity; used within the package 1171 * 1172 * @param guid 1173 * String representation of guid 1174 */ 1175 protected void setGuid(Guid guid) { 1176 1177 m_guid = guid; 1178 } 1179 1180 /** 1181 * Return the authenticated principal that is used to instantiate this 1182 * object 1183 * 1184 * @return authenticated principal that is used to instantiate this object, 1185 * return null if no authenticated principal is associated with this 1186 * object 1187 */ 1188 Principal getPrincipal() { 1189 return m_principal; 1190 } 1191 1192 /** 1193 * Set current authenticated session; used within the package 1194 * 1195 * @param session 1196 * A valid authenticated session 1197 */ 1198 void setPrincipal(Principal principal) { 1199 m_principal = principal; 1200 } 1201 1202 /** 1203 * Sets the attribute set 1204 * 1205 * @param attrSet 1206 * The attribute set to be assigned as a reference (not a deep 1207 * copy) 1208 */ 1209 protected void setAttrSet(AttrSet attrSet) { 1210 m_attrSet = attrSet; 1211 } 1212 1213 /** 1214 * Gets the attribute set as a reference, not a deep copy 1215 * 1216 * @return The in-memory attribute set 1217 */ 1218 protected AttrSet getAttrSet() { 1219 return m_attrSet; 1220 } 1221 1222 /** 1223 * Checks if javaclass of the persistent object is the expected class 1224 * defined in its objectclass attribute. 1225 * 1226 * @throws UMSException 1227 * when the objectclass maps to a javaclass different from the 1228 * one being constructed. 1229 * @see com.iplanet.ums.TempateManager#getJavaClassForEntry 1230 */ 1231 void verifyClass() throws UMSException { 1232 Class expectedClass = 1233 TemplateManager.getTemplateManager().getJavaClassForEntry( 1234 this.getGuid().getDn(), this.getAttrSet()); 1235 1236 // TODO: need to be reviewed and see if subclasses of entity are 1237 // allowed. 1238 // e.g. PersistentObject -> User -> MailUser kind of inheritence, do we 1239 // accept the formation of User class for MailUser. 1240 // 1241 if (this.getClass() != expectedClass) { 1242 String msg = i18n.getString(IUMSConstants.UNMATCHED_CLASS); 1243 // TODO: review for better exception 1244 throw new IllegalArgumentException(msg); 1245 } 1246 } 1247 1248 /** 1249 * Maps to a DN from naming attribute value of a persistent object. 1250 * 1251 * @param namingAttribute Naming attribute of the object. 1252 * @param name Naming attribute value of the object. 1253 * @param parentID Array of its parent names, all assumed to take 1254 * <code>o</code> as the naming attributes. 1255 */ 1256 static public String idToDN( 1257 String namingAttribute, 1258 String name, 1259 String[] parentID 1260 ) { 1261 StringBuilder sb = new StringBuilder(); 1262 1263 sb.append(namingAttribute).append("=").append(name); 1264 for (int i = 0; i < parentID.length; i++) { 1265 if (parentID[i] != null) { 1266 // TODO: ??? This is hardcoded to take "o=something" as the 1267 // parent node(s). Needs a flexible scheme to handle 1268 // flexible DIT. 1269 sb.append(",o=").append(parentID[i]); 1270 } 1271 } 1272 1273 return sb.toString(); 1274 } 1275 1276 /** 1277 * Maps a dn to guid 1278 * <P> 1279 * TODO: Not yet implemented 1280 * <P> 1281 */ 1282 static String dnToGuid(String dn) { 1283 // TODO: Need to fill in base 64 encoding <P> 1284 // 1285 return dn; 1286 } 1287 1288 /** 1289 * Maps a guid to dn 1290 * <P> 1291 * TODO: Not yet implemented 1292 * <P> 1293 */ 1294 static String guidToDN(String guid) { 1295 // TODO: Need to fill in base 64 encoding <P> 1296 // 1297 return guid; 1298 } 1299 1300 /** 1301 * Reads in the object from persistent store, assuming that the guid and 1302 * session are valid 1303 * 1304 * @throws UMSException 1305 * on failure in reading the object from persistent store 1306 */ 1307 synchronized private void read() throws UMSException { 1308 if (m_principal == null || m_guid == null) { 1309 // TODO: there should be some warning to the client here 1310 return; 1311 } 1312 1313 m_attrSet = DataLayer.getInstance().read(getPrincipal(), getGuid()); 1314 } 1315 1316 private void checkCache() { 1317 if (m_principal != null && m_guid != null && m_attrSet == null) { 1318 try { 1319 read(); 1320 } catch (UMSException e) { 1321 // TODO: there should be some warning to the client here 1322 if (debug.messageEnabled()) { 1323 debug.message("PersistentObject.checkCache() : " + 1324 "UMSException : " + e.getMessage()); 1325 } 1326 } 1327 } 1328 } 1329 1330 /** 1331 * Internal use only, set the internal modset. Can be used to nullify the 1332 * internal state of m_modSet 1333 * 1334 * @param modSet 1335 * Modification Set to be used for the internal 1336 * <code>modSet</code>. 1337 */ 1338 void setModSet(Collection<Modification> modSet) { 1339 m_modSet = modSet; 1340 } 1341 1342 /** 1343 * Checks if this object is a member of an IMembership. Roles and Groups 1344 * implement IMembership 1345 * 1346 * @param im 1347 * Role or Group against which the membership is to be checked 1348 * @return <code>true</code> if this object is a member of the 1349 * IMembership, <code>false</code> otherwise 1350 * @throws UMSException 1351 * propagates any exception from the datalayer 1352 * 1353 * @supported.api 1354 */ 1355 public boolean isMemberOf(IMembership im) throws UMSException { 1356 return im.hasMember(getGuid()); 1357 } 1358 1359 /** 1360 * Gets the list of GUIDS roles assosciated with this object 1361 * 1362 * @return list that lets iterating over role GUIDs 1363 * @throws UMSException 1364 * propagates any exception from the datalayer 1365 * 1366 * @supported.api 1367 */ 1368 public Collection getRoles() throws UMSException { 1369 ArrayList roleList = new ArrayList(); 1370 Attr roleAttr = getAttribute(COMPUTED_MEMBER_ATTR_NAME); 1371 if (roleAttr != null && roleAttr.getStringValues() != null) { 1372 roleList.addAll(Arrays.asList(roleAttr.getStringValues())); 1373 } 1374 return roleList; 1375 } 1376 1377 /** 1378 * Returns all the ACIs of this object. 1379 * 1380 * @return collecion of ACIs of this object. 1381 * @throws ACIParseException if any error 1382 * 1383 * @supported.api 1384 */ 1385 public Collection getACI() throws ACIParseException, UMSException { 1386 Collection acis = new ArrayList(); 1387 Attr aciAttr = getAttribute(ACI.ACI); 1388 if (aciAttr != null) { 1389 String[] aciTexts = aciAttr.getStringValues(); 1390 int size = aciTexts.length; 1391 for (int i = 0; i < size; i++) { 1392 acis.add(ACI.valueOf(aciTexts[i])); 1393 } 1394 } 1395 return acis; 1396 } 1397 1398 /** 1399 * Returns all the ACIs of this object with the given name. 1400 * 1401 * @param name Name of the ACI to get. 1402 * @return collecion of ACIs of this object. 1403 * @throws ACIParseException in case of any error 1404 * 1405 * @supported.api 1406 */ 1407 public Collection getACI(String name) throws ACIParseException, 1408 UMSException { 1409 Collection acis = new ArrayList(); 1410 Attr aciAttr = getAttribute(ACI.ACI); 1411 if (aciAttr != null) { 1412 String[] aciTexts = aciAttr.getStringValues(); 1413 int size = aciTexts.length; 1414 for (int i = 0; i < size; i++) { 1415 ACI aci = ACI.valueOf(aciTexts[i]); 1416 if (aci.getName().equals(name)) { 1417 acis.add(aci); 1418 } 1419 } 1420 } 1421 return acis; 1422 } 1423 1424 /** 1425 * Adds an ACI to this object. 1426 * 1427 * @param aci ACI added to be added to this object. 1428 * @throws AccessRightsException if an access rights exception occurs. 1429 * @throws UMSException if any error 1430 * 1431 * @supported.api 1432 */ 1433 public void addACI(ACI aci) throws AccessRightsException, UMSException { 1434 Attr attr = new Attr(ACI.ACI, aci.toString()); 1435 modify(attr, ModificationType.ADD); 1436 save(); 1437 } 1438 1439 /** 1440 * Deletes an ACI of this object 1441 * 1442 * @param aci ACI to be deleted. 1443 * @throws AccessRightsException if an access rights exception occurs. 1444 * @throws UMSException if any error. 1445 * 1446 * @supported.api 1447 */ 1448 public void deleteACI(ACI aci) throws AccessRightsException, UMSException { 1449 Attr attr = new Attr(ACI.ACI, aci.getACIText()); 1450 modify(attr, ModificationType.DELETE); 1451 save(); 1452 } 1453 1454 /** 1455 * Replaces an ACI of this object 1456 * 1457 * @param oldACI ACI to be replaced. 1458 * @param newACI the new ACI. 1459 * @throws AccessRightsException if an access rights exception occurs. 1460 * @throws UMSException if any error. 1461 * 1462 * @supported.api 1463 */ 1464 public void replaceACI(ACI oldACI, ACI newACI) 1465 throws AccessRightsException, UMSException { 1466 Attr attr = new Attr(ACI.ACI, oldACI.getACIText()); 1467 modify(attr, ModificationType.DELETE); 1468 attr = new Attr(ACI.ACI, newACI.toString()); 1469 modify(attr, ModificationType.ADD); 1470 save(); 1471 } 1472 1473 /** 1474 * Adds value for an attribute and saves the change in the database. 1475 * 1476 * @param token Authenticated prinicpal's single sign on token. 1477 * @param guid Identifiation of the entry to which to add the attribute 1478 * value. 1479 * @param name Name of the attribute to which value is being added. 1480 * @param value Value to be added to the attribute. 1481 * @throws UMSException if any exception from the data layer. 1482 * 1483 * @supported.api 1484 */ 1485 public static void addAttributeValue( 1486 SSOToken token, 1487 Guid guid, 1488 String name, 1489 String value 1490 ) throws UMSException { 1491 if (guid == null) { 1492 throw new IllegalArgumentException(i18n 1493 .getString(IUMSConstants.NULL_GUIDS)); 1494 } 1495 if (token == null) { 1496 throw new IllegalArgumentException(i18n 1497 .getString(IUMSConstants.NULL_TOKEN)); 1498 } 1499 try { 1500 SSOTokenManager.getInstance().validateToken(token); 1501 } catch (SSOException se) { 1502 throw new UMSException(i18n.getString(IUMSConstants.INVALID_TOKEN), 1503 se); 1504 } 1505 1506 Attr attr = new Attr(name, value); 1507 attr = null; 1508 Validation.validateAttribute(attr, UMSObject.getObject(token, guid) 1509 .getClass(), guid); 1510 try { 1511 DataLayer.getInstance().addAttributeValue(token.getPrincipal(), 1512 guid, name, value); 1513 } catch (SSOException se) { 1514 throw new UMSException(i18n.getString(IUMSConstants.BAD_TOKEN_HDL), 1515 se); 1516 } 1517 } 1518 1519 /** 1520 * Removes value for an attribute and saves the change in the database. 1521 * 1522 * @param token Authenticated prinicpal's single sign on token. 1523 * @param guid Identification of the entry from which to remove the 1524 * attribute value. 1525 * @param name Name of the attribute from which value is being removed. 1526 * @param value Value to be removed from the attribute. 1527 * @throws UMSException if any exception from the data layer. 1528 * 1529 * @supported.api 1530 */ 1531 public static void removeAttributeValue(SSOToken token, Guid guid, 1532 String name, String value) throws UMSException { 1533 if (guid == null) { 1534 throw new IllegalArgumentException(i18n 1535 .getString(IUMSConstants.NULL_GUIDS)); 1536 } 1537 if (token == null) { 1538 throw new IllegalArgumentException(i18n 1539 .getString(IUMSConstants.NULL_TOKEN)); 1540 } 1541 try { 1542 SSOTokenManager.getInstance().validateToken(token); 1543 } catch (SSOException se) { 1544 throw new UMSException(i18n.getString(IUMSConstants.INVALID_TOKEN), 1545 se); 1546 } 1547 1548 try { 1549 DataLayer.getInstance().removeAttributeValue(token.getPrincipal(), 1550 guid, name, value); 1551 } catch (SSOException se) { 1552 throw new UMSException(i18n.getString(IUMSConstants.BAD_TOKEN_HDL), 1553 se); 1554 } 1555 } 1556 1557 /** 1558 * Check if the object is persistent in the system 1559 * 1560 * @return true if the object is persistent in the system and false 1561 * otherwise 1562 */ 1563 protected boolean isPersistent() { 1564 return m_principal != null && m_guid != null 1565 && m_guid.getDn().length() > 0; 1566 } 1567 1568 /** 1569 * Find the names of attributes not read from data store so far 1570 * 1571 * @param attrNames 1572 * names of attributes to get 1573 * @return collection of names of attributes not read from data store so far 1574 */ 1575 private Collection findAttributesNotRead(String[] attrNames) { 1576 ArrayList attributesNotInCache = new ArrayList(); 1577 if (m_attrSet == null) { 1578 m_attrSet = new AttrSet(); 1579 } 1580 if (m_nullAttributes == null) { 1581 m_nullAttributes = new ArrayList(); 1582 } 1583 int length = attrNames.length; 1584 for (int i = 0; i < length; i++) { 1585 if ((m_attrSet.getAttribute(attrNames[i]) == null) 1586 && !m_nullAttributes.contains(attrNames[i])) { 1587 attributesNotInCache.add(attrNames[i]); 1588 } 1589 } 1590 return attributesNotInCache; 1591 } 1592 1593 /** 1594 * Find whether the attribute was not read from data store so far 1595 * 1596 * @param attrName 1597 * name of attribute to check 1598 * @return <code>true</code> if the attribute was not read, otherwise 1599 * <code>false</code> 1600 */ 1601 private boolean isAttributeNotRead(String attrName) { 1602 boolean attributeNotRead = false; 1603 if (m_attrSet == null) { 1604 m_attrSet = new AttrSet(); 1605 } 1606 if (m_nullAttributes == null) { 1607 m_nullAttributes = new ArrayList(); 1608 } 1609 if ((m_attrSet.getAttribute(attrName) == null) 1610 && !m_nullAttributes.contains(attrName)) { 1611 attributeNotRead = true; 1612 } 1613 return attributeNotRead; 1614 } 1615 1616 /** 1617 * Read the attributes from data store 1618 * 1619 * @param attrNames 1620 * names of attributes to get 1621 * @return collection of Attr read from data store 1622 */ 1623 private Collection readAttributesFromDataStore(Collection attrNames) 1624 throws UMSException { 1625 Collection attributes = DataLayer.getInstance().getAttributes( 1626 getPrincipal(), getGuid(), attrNames); 1627 if (attributes == null) { 1628 String[] args = { getDN() }; 1629 throw new UMSException(i18n.getString( 1630 IUMSConstants.READ_ATTRIBUTES_ERROR, args)); 1631 } 1632 Collection foundAttributes = new ArrayList(); 1633 if (m_attrSet == null) { 1634 m_attrSet = new AttrSet(); 1635 } 1636 if (m_nullAttributes == null) { 1637 m_nullAttributes = new ArrayList(); 1638 } 1639 Iterator iter = attributes.iterator(); 1640 while (iter.hasNext()) { 1641 Attr attr = (Attr) iter.next(); 1642 foundAttributes.add(attr.getName()); 1643 m_attrSet.replace(attr); 1644 } 1645 iter = attrNames.iterator(); 1646 while (iter.hasNext()) { 1647 String attrName = (String) iter.next(); 1648 if (!foundAttributes.contains(attrName) 1649 && !m_nullAttributes.contains(attrName)) { 1650 m_nullAttributes.add(attrName); 1651 } 1652 } 1653 return attributes; 1654 } 1655 1656 /** 1657 * Read the attribute from data store 1658 * 1659 * @param attrName 1660 * names of attributes to get 1661 * @return Attr read from datastore 1662 */ 1663 private Attr readAttributeFromDataStore(String attrName) throws UMSException { 1664 Attr attr = DataLayer.getInstance().getAttribute(getPrincipal(), 1665 getGuid(), attrName); 1666 if (m_attrSet == null) { 1667 m_attrSet = new AttrSet(); 1668 } 1669 if (m_nullAttributes == null) { 1670 m_nullAttributes = new ArrayList(); 1671 } 1672 if (attr != null) { 1673 m_attrSet.replace(attr); 1674 } else if (!m_nullAttributes.contains(attrName)) { 1675 m_nullAttributes.add(attrName); 1676 } 1677 return attr; 1678 } 1679 1680 /** 1681 * Get the attribute from cache, does not read data store 1682 * 1683 * @param attrName 1684 * name of attribute to get 1685 * @return Attr read from cache 1686 */ 1687 private Attr getAttributeFromCache(String attrName) { 1688 Attr attr = null; 1689 if (m_attrSet != null) { 1690 attr = m_attrSet.getAttribute(attrName); 1691 } 1692 return attr; 1693 } 1694 1695 /** 1696 * Authenticated session in constructing the object 1697 * 1698 * @serial 1699 */ 1700 private Principal m_principal; 1701 1702 /** 1703 * Identification of the object 1704 * 1705 * @serial 1706 */ 1707 private Guid m_guid; 1708 1709 /** 1710 * Internal cache for attributes 1711 * 1712 * @serial 1713 */ 1714 private AttrSet m_attrSet; 1715 1716 /** 1717 * Internal cache for attributes read from directory and found to be null 1718 * 1719 * @serial 1720 */ 1721 private ArrayList m_nullAttributes; 1722 1723 /** 1724 * Internal cache for changes made to the object 1725 * 1726 * @serial 1727 */ 1728 private Collection<Modification> m_modSet; 1729 1730 /** 1731 * Internal naming attribute (ex: "ou") 1732 * 1733 * @serial 1734 */ 1735 private String m_namingAttribute = null; 1736}