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