/**
  * Method to be called to validate the entry before any of the get/put/ remove methods are called.
  *
  * @throws AMException if the entry does not exist in the DS
  */
 private void validateEntry(SSOToken token, CacheBlock cb) throws AMException {
   if (!cb.hasExpiredAndUpdated() && !cb.isExists()) {
     // Entry does not exist in DS, invalid entry
     String params[] = {cb.getEntryDN()};
     boolean isPresent = super.doesEntryExists(token, params[0]);
     if (getDebug().messageEnabled()) {
       getDebug()
           .message(
               "CachedRemoteServicesImpl.validateEntry():"
                   + " DN"
                   + params[0]
                   + " got from DS & exists: "
                   + isPresent);
     }
     if (isPresent) {
       // Intialize the CacheBlock based on isPresent
       // else throw '461' exception/error message.
       // This is for certain containers created dynamically.
       // eg. ou=agents,ou=container,ou=agents.
       String dn = MiscUtils.formatToRFC(params[0]);
       cb = new CacheBlock(params[0], isPresent);
       sdkCache.put(dn, cb);
     } else {
       String locale = MiscUtils.getUserLocale(token);
       throw new AMException(AMSDKBundle.getString("461", params, locale), "461", params);
     }
   }
 }
 /** Method that updates the cache entries locally. This method does a write through cache */
 private void updateCache(SSOToken token, String dn, Map stringAttributes, Map byteAttributes)
     throws SSOException {
   String key = MiscUtils.formatToRFC(dn);
   CacheBlock cb = (CacheBlock) sdkCache.get(key);
   if (cb != null && !cb.hasExpiredAndUpdated() && cb.isExists()) {
     String pDN = MiscUtils.getPrincipalDN(token);
     cb.replaceAttributes(pDN, stringAttributes, byteAttributes);
   }
 }
 private void dirtyCache(String dn) {
   String key = MiscUtils.formatToRFC(dn);
   CacheBlock cb = (CacheBlock) sdkCache.get(key);
   if (cb != null) {
     cb.clear();
   }
 }
 /**
  * Renames an entry. Currently used for only user renaming.
  *
  * @param token the sso token
  * @param objectType the type of entry
  * @param entryDN the entry DN
  * @param newName the new name (i.e., if RDN is cn=John, the value passed should be "John"
  * @param deleteOldName if true the old name is deleted otherwise it is retained.
  * @return new <code>DN</code> of the renamed entry
  * @throws AMException if the operation was not successful
  */
 public String renameEntry(
     SSOToken token, int objectType, String entryDN, String newName, boolean deleteOldName)
     throws AMException {
   String newDN = super.renameEntry(token, objectType, entryDN, newName, deleteOldName);
   // Just rename the dn in the cache. Don't remove the entry. So when the
   // event notification happens, it won't find the entry as it is already
   // renamed. Chances are this cache rename operation may happen before
   // the notification thread trys clean up.
   // NOTE: We should have the code to remove the entry for rename
   // operation as the operation could have been performed by some other
   // process such as amadmin.
   String oldDN = MiscUtils.formatToRFC(entryDN);
   CacheBlock cb = (CacheBlock) sdkCache.remove(oldDN);
   newDN = MiscUtils.formatToRFC(newDN);
   sdkCache.put(newDN, cb);
   return newDN;
 }
 private void dirtyCache(Set entries) {
   Iterator itr = entries.iterator();
   while (itr.hasNext()) {
     String entryDN = (String) itr.next();
     String key = MiscUtils.formatToRFC(entryDN);
     CacheBlock cb = (CacheBlock) sdkCache.get(key);
     if (cb != null) {
       cb.clear();
     }
   }
 }
  /**
   * Gets the type of the object given its DN.
   *
   * @param token token a valid SSOToken
   * @param dn DN of the object whose type is to be known.
   * @throws AMException if the data store is unavailable or if the objecttype is unknown
   * @throws SSOException if ssoToken is invalid or expired.
   */
  public int getObjectType(SSOToken token, String dn) throws AMException, SSOException {
    int objectType = AMObject.UNDETERMINED_OBJECT_TYPE;
    String entryDN = MiscUtils.formatToRFC(dn);
    CacheBlock cb = (CacheBlock) sdkCache.get(entryDN);
    if (cb != null) {
      // Check if the entry exists, if not present throw an exception
      if (!doesEntryExists(token, dn)) {
        String locale = MiscUtils.getUserLocale(token);
        String params[] = {cb.getEntryDN()};
        throw new AMException(AMSDKBundle.getString("461", params, locale), "461", params);
      }
      validateEntry(token, cb);
      objectType = cb.getObjectType();
      if (objectType != AMObject.UNDETERMINED_OBJECT_TYPE) {
        return objectType;
      }
    }

    // Use admintoken to get object type, so that it can be cached
    SSOToken adminToken = (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());

    // The method below will throw an AMException if the entry does not
    // exist in the directory. If it exists, then create a cache entry for
    // this DN
    if (cb == null) {
      objectType = super.getObjectType(adminToken, entryDN);
      cb = new CacheBlock(entryDN, true);
      sdkCache.put(entryDN, cb);
    } else {
      objectType =
          super.getObjectType(
              adminToken, entryDN, cb.getAttributes(MiscUtils.getPrincipalDN(adminToken), false));
    }
    cb.setObjectType(objectType);
    if (objectType == AMObject.ORGANIZATION || objectType == AMObject.ORGANIZATIONAL_UNIT) {
      cb.setOrganizationDN(entryDN);
    }
    return objectType;
  }
 /**
  * Create an AMTemplate (COSTemplate)
  *
  * @param token token
  * @param entryDN DN of the profile whose template is to be set
  * @param objectType the object type
  * @param serviceName Service Name
  * @param attributes attributes to be set
  * @param priority template priority
  * @return String DN of the newly created template
  */
 public String createAMTemplate(
     SSOToken token,
     String entryDN,
     int objectType,
     String serviceName,
     Map attributes,
     int priority)
     throws AMException {
   String templateDN =
       super.createAMTemplate(token, entryDN, objectType, serviceName, attributes, priority);
   // Mark the entry as exists in cache
   String dn = MiscUtils.formatToRFC(templateDN);
   CacheBlock cb = (CacheBlock) sdkCache.get(dn);
   if (cb != null) {
     cb.setExists(true);
   }
   return templateDN;
 }
 public boolean doesEntryExists(SSOToken token, String entryDN) {
   String dn = MiscUtils.formatToRFC(entryDN);
   CacheBlock cb = (CacheBlock) sdkCache.get(dn);
   if (cb != null && !cb.hasExpiredAndUpdated()) {
     if (getDebug().messageEnabled()) {
       getDebug()
           .message(
               "CachedRemoteServicesImpl."
                   + "doesEntryExist(): entryDN: "
                   + entryDN
                   + " found in cache & exists: "
                   + cb.isExists());
     }
     return cb.isExists();
   } else {
     boolean isPresent = super.doesEntryExists(token, dn);
     if (getDebug().messageEnabled()) {
       getDebug()
           .message(
               "CachedRemoteServicesImpl."
                   + "doesEntryExist(): entryDN: "
                   + entryDN
                   + " got from DS & exists: "
                   + isPresent);
     }
     // Intialize the CacheBock based on isPresent
     // Intialize the CacheBock based on isPresent
     if (cb == null) {
       cb = new CacheBlock(entryDN, isPresent);
       sdkCache.put(dn, cb);
     } else { // Cache Block might have just expired, just reset the
       // isExists flag once again
       cb.setExists(isPresent);
     }
     return isPresent;
   }
 }
  /**
   * Gets the specific attributes corresponding to the entryDN. This method obtains the DC Tree node
   * attributes and also performs compliance related verification checks in compliance mode. Note:
   * In compliance mode you can skip the compliance checks by setting ignoreCompliance to "false".
   *
   * @param token a valid SSOToken
   * @param entryDN the DN of the entry whose attributes need to retrieved
   * @param attrNames a Set of names of the attributes that need to be retrieved. The attrNames
   *     should not be null
   * @param ignoreCompliance a boolean value specificying if compliance related entries need to
   *     ignored or not. Ignored if true.
   * @return a Map containing attribute names as keys and Set of values corresponding to each key.
   * @throws AMException if an error is encountered in fetching the attributes
   */
  public Map getAttributes(
      SSOToken token,
      String entryDN,
      Set attrNames,
      boolean ignoreCompliance,
      boolean byteValues,
      int profileType)
      throws AMException, SSOException {
    if (attrNames == null || attrNames.isEmpty()) {
      return getAttributes(token, entryDN, ignoreCompliance, byteValues, profileType);
    }

    // Attributes are being requested; increment cache stats request counter
    cacheStats.incrementRequestCount(getSize());

    // Load the whole attrset in the cache, if in DCTree mode
    // Not good for performance, but fix later TODO (Deepa)
    if (dcTreeServicesImpl.isRequired()) { // TODO: This needs to be fixed!
      getAttributes(token, entryDN, ignoreCompliance, byteValues, profileType);
    }

    String principalDN = MiscUtils.getPrincipalDN(token);
    if (getDebug().messageEnabled()) {
      getDebug()
          .message(
              "In CachedRemoteServicesImpl.getAttributes("
                  + "SSOToken entryDN, attrNames, ignoreCompliance, "
                  + "byteValues) "
                  + "("
                  + principalDN
                  + ", "
                  + entryDN
                  + ", "
                  + attrNames
                  + ", "
                  + ignoreCompliance
                  + ", "
                  + byteValues
                  + " method.");
    }

    String dn = MiscUtils.formatToRFC(entryDN);
    CacheBlock cb = (CacheBlock) sdkCache.get(dn);
    if (cb == null) { // Entry not present in cache
      if (getDebug().messageEnabled()) {
        getDebug()
            .message(
                "CachedRemoteServicesImpl."
                    + "getAttributes():  NO entry found in Cache. Getting"
                    + " all these attributes from DS: "
                    + attrNames);
      }

      // If the attributes returned here have an empty set as value, then
      // such attributes do not have a value or invalid attributes.
      // Internally keep track of these attributes.
      AMHashMap attributes =
          (AMHashMap)
              super.getAttributes(
                  token, entryDN, attrNames, ignoreCompliance, byteValues, profileType);

      // These attributes are either not present or not found in DS.
      // Try to check if they need to be fetched by external
      // plugins
      Set missAttrNames = attributes.getMissingAndEmptyKeys(attrNames);
      cb = new CacheBlock(dn, true);
      cb.putAttributes(principalDN, attributes, missAttrNames, false, byteValues);
      sdkCache.put(dn, cb);

      if (!missAttrNames.isEmpty()) {
        attributes =
            getPluginAttrsAndUpdateCache(
                token,
                principalDN,
                entryDN,
                cb,
                attributes,
                missAttrNames,
                byteValues,
                profileType);
      }
      return attributes;
    } else { // Entry present in cache
      validateEntry(token, cb); // Entry may be an invalid entry
      AMHashMap attributes = (AMHashMap) cb.getAttributes(principalDN, attrNames, byteValues);

      // Find the missing attributes that need to be obtained from DS
      // Only find the missing keys as the ones with empty sets are not
      // found in DS
      Set missAttrNames = attributes.getMissingKeys(attrNames);
      if (!missAttrNames.isEmpty()) {
        boolean isComplete = cb.hasCompleteSet(principalDN);
        AMHashMap dsAttributes = null;
        if (!isComplete
            ||
            // Check for "nsRole" and "nsRoleDN" attributes
            missAttrNames.contains(NSROLEDN_ATTR)
            || missAttrNames.contains(NSROLE_ATTR)) {
          if (getDebug().messageEnabled()) {
            getDebug()
                .message(
                    "CachedRemoteServicesImpl."
                        + "getAttributes(): Trying to get these missing"
                        + " attributes from DS: "
                        + missAttrNames);
          }

          dsAttributes =
              (AMHashMap)
                  super.getAttributes(
                      token, entryDN, missAttrNames, ignoreCompliance, byteValues, profileType);

          if (dsAttributes != null) {
            attributes.putAll(dsAttributes);
            // Add these attributes, may be found in DS or just mark
            // as invalid (Attribute level Negative caching)
            Set newMissAttrNames = dsAttributes.getMissingAndEmptyKeys(missAttrNames);

            // Update dsAttributes with rest of the attributes
            // in cache
            dsAttributes.putAll(cb.getAttributes(principalDN, byteValues));

            // Update the cache
            cb.putAttributes(principalDN, dsAttributes, newMissAttrNames, isComplete, byteValues);
            missAttrNames = newMissAttrNames;
          }
        } else {
          // Update cache with invalid attributes
          cb.putAttributes(
              principalDN,
              cb.getAttributes(principalDN, byteValues),
              missAttrNames,
              isComplete,
              byteValues);
        }
        if (!missAttrNames.isEmpty()) {
          attributes =
              getPluginAttrsAndUpdateCache(
                  token,
                  principalDN,
                  entryDN,
                  cb,
                  attributes,
                  missAttrNames,
                  byteValues,
                  profileType);
        }
      } else { // All attributes found in cache
        if (getDebug().messageEnabled()) {
          getDebug()
              .message(
                  "CachedRemoteServicesImpl."
                      + "getAttributes():  found all attributes in "
                      + "Cache.");
        }
        cacheStats.updateHitCount(getSize());
      }
      // Remove all the empty values from the return attributes
      return attributes;
    }
  }
  /**
   * Gets all attributes corresponding to the entryDN. This method obtains the DC Tree node
   * attributes and also performs compliance related verification checks in compliance mode. Note:
   * In compliance mode you can skip the compliance checks by setting ignoreCompliance to "false".
   *
   * @param token a valid SSOToken
   * @param entryDN the DN of the entry whose attributes need to retrieved
   * @param ignoreCompliance a boolean value specificying if compliance related entries need to
   *     ignored or not. Ignored if true.
   * @param byteValues if false StringValues are fetched, if true byte values are fetched.
   * @param profileType the oject type of entryDN
   * @return a Map containing attribute names as keys and Set of values corresponding to each key.
   * @throws AMException if an error is encountered in fetching the attributes
   */
  public Map getAttributes(
      SSOToken token, String entryDN, boolean ignoreCompliance, boolean byteValues, int profileType)
      throws AMException, SSOException {
    // Attributes are being requested; increment cache stats request counter
    cacheStats.incrementRequestCount(getSize());

    String principalDN = MiscUtils.getPrincipalDN(token);
    String dn = MiscUtils.formatToRFC(entryDN);

    if (getDebug().messageEnabled()) {
      getDebug()
          .message(
              "In CachedRemoteServicesImpl.getAttributes("
                  + "SSOToken entryDN, ignoreCompliance) "
                  + "("
                  + principalDN
                  + ", "
                  + entryDN
                  + ", "
                  + ignoreCompliance
                  + " method.");
    }

    CacheBlock cb = (CacheBlock) sdkCache.get(dn);
    AMHashMap attributes = null;
    if (cb != null) {
      validateEntry(token, cb);
      if (cb.hasCompleteSet(principalDN)) {
        cacheStats.updateHitCount(getSize());
        if (getDebug().messageEnabled()) {
          getDebug()
              .message(
                  "CachedRemoteServicesImpl."
                      + "getAttributes(): found all attributes in "
                      + "Cache.");
        }
        attributes = (AMHashMap) cb.getAttributes(principalDN, byteValues);
      } else { // Get the whole set from DS and store it;
        // ignore incomplete set
        if (getDebug().messageEnabled()) {
          getDebug()
              .message(
                  "CachedRemoteServicesImpl."
                      + "getAttributes():  complete attribute set NOT "
                      + "found in cache. Getting from DS.");
        }

        attributes =
            (AMHashMap)
                super.getAttributes(token, entryDN, ignoreCompliance, byteValues, profileType);
        cb.putAttributes(principalDN, attributes, null, true, byteValues);
      }
    } else { // Attributes not cached
      // Get all the attributes from DS and store them
      attributes =
          (AMHashMap)
              super.getAttributes(token, entryDN, ignoreCompliance, byteValues, profileType);
      cb = new CacheBlock(entryDN, true);
      cb.putAttributes(principalDN, attributes, null, true, byteValues);
      sdkCache.put(dn, cb);

      if (getDebug().messageEnabled()) {
        getDebug()
            .message(
                "CachedRemoteServicesImpl."
                    + "getAttributes(): attributes NOT found in cache. "
                    + "Fetched from DS.");
      }
    }

    // Get all external DS attributes by calling plugin modules.
    // Note these attributes should not be cached.
    Map extAttributes = getExternalAttributes(token, entryDN, null, profileType);
    if (extAttributes != null && !extAttributes.isEmpty()) {
      // Note the attributes stored in the cache are already copied to a
      // new map. Hence modifying this attributes is okay.
      if (getDebug().messageEnabled()) {
        getDebug()
            .message(
                "CachedRemoteServicesImpl."
                    + "getAttributes(): External attributes present. Adding"
                    + " them with original list");
      }
      attributes.putAll(extAttributes);
    }
    return attributes;
  }
 private synchronized void removeFromCache(String dn) {
   String key = MiscUtils.formatToRFC(dn);
   sdkCache.remove(key);
 }
 /**
  * This method will be called by <code>AMIdRepoListener</code>. This method will update the cache
  * by removing all the entires which are affected as a result of an event notification caused
  * because of changes/deletions/renaming of entries with and without aci's.
  *
  * <p>NOTE: The event could have been caused either by changes to an aci entry or a costemplate or
  * a cosdefinition or changes to a normal entry
  *
  * @param dn name of entity being modified
  * @param eventType type of modification
  * @param cosType true if it is cos related. false otherwise
  * @param aciChange true if it is aci related. false otherwise
  * @param attrNames Set of attribute Names which should be removed from the CacheEntry in the case
  *     of COS change
  */
 public void dirtyCache(
     String dn, int eventType, boolean cosType, boolean aciChange, Set attrNames) {
   CacheBlock cb;
   String origdn = dn;
   dn = MiscUtils.formatToRFC(dn);
   switch (eventType) {
     case AMEvent.OBJECT_ADDED:
       cb = (CacheBlock) sdkCache.get(dn);
       if (cb != null) { // Mark an invalid entry as valid now
         cb.setExists(true);
       }
       if (cosType) { // A cos type event remove all affected attributes
         removeCachedAttributes(dn, attrNames);
       }
       break;
     case AMEvent.OBJECT_REMOVED:
       cb = (CacheBlock) sdkCache.remove(dn);
       if (cb != null) {
         cb.clear(); // Clear anyway & help the GC process
       }
       if (cosType) {
         removeCachedAttributes(dn, attrNames);
       }
       break;
     case AMEvent.OBJECT_RENAMED:
       // Better to remove the renamed entry, or else it will be just
       // hanging in the cache, until LRU kicks in.
       cb = (CacheBlock) sdkCache.remove(dn);
       if (cb != null) {
         cb.clear(); // Clear anyway & help the GC process
       }
       if (cosType) {
         removeCachedAttributes(dn, attrNames);
       }
       break;
     case AMEvent.OBJECT_CHANGED:
       cb = (CacheBlock) sdkCache.get(dn);
       if (cb != null) {
         cb.clear(); // Just clear the entry. Don't remove.
       }
       if (cosType) {
         removeCachedAttributes(dn, attrNames);
       } else if (aciChange) { // Clear all affected entries
         clearCachedEntries(dn);
       }
       break;
   }
   if (getDebug().messageEnabled()) {
     getDebug()
         .message(
             "CachedRemoteServicesImpl.dirtyCache(): "
                 + "Cache dirtied because of Event Notification. Parameters"
                 + " - eventType: "
                 + eventType
                 + ", cosType: "
                 + cosType
                 + ", aciChange: "
                 + aciChange
                 + ", fullDN: "
                 + origdn
                 + "; rfcDN ="
                 + dn);
   }
 }