/**
   * Method to get search filter for the specified object type defined at the specified
   * Organization. If a search template corresponding to the AMObject, is not found at the specified
   * Organization, then one defined at global one will be returned.
   *
   * @param objectType type of AMObject
   * @param orgDN the DN of the organization where the AMObject resides.
   * @param searchTemplateName name of the search template to be used. If this is null, then default
   *     search templates are used.
   * @param ignoreComplianceFilter if true then modify the compliance related search filters will
   *     not be applied. If false, compliance related filters will be applied.
   * @return a search filter String in lower case.
   */
  public static String getSearchFilter(
      int objectType, String orgDN, String searchTemplateName, boolean ignoreComplianceFilter) {
    String filter;
    String organizationDN = new DN(orgDN).toRFCString();
    // Already in RFC
    String rootSuffixDN = AMStoreConnection.getAMSdkBaseDN();
    if (orgDN != null && organizationDN.equals(rootSuffixDN)) {
      orgDN = null;
    }
    String cacheKey =
        (new Integer(objectType)).toString() + ":" + searchTemplateName + ":" + organizationDN;
    if ((filter = (String) searchfilterMap.get(cacheKey)) == null) {
      IDirectoryServices dsServices = AMDirectoryAccessFactory.getDirectoryServices();
      filter = dsServices.getSearchFilterFromTemplate(objectType, orgDN, searchTemplateName);
      searchfilterMap.put(cacheKey, filter);
    }

    // Now modify the obtained search filter if necessary. Also, mostly
    // do the modification here, if you do not want the modified filter
    // to be cached. Applicable to cases where filter may change dynamically
    // Note: Always add lowercase filters, to guarantee a lowercase filter
    // String to be returned.
    filter = modifyFilter(filter, objectType);
    filter = addAdminGroupFilters(filter, orgDN, objectType);
    filter = addComplianceModeFilters(filter, objectType, ignoreComplianceFilter);
    return filter;
  }
 private void dirtyCache(String dn) {
   String key = MiscUtils.formatToRFC(dn);
   CacheBlock cb = (CacheBlock) sdkCache.get(key);
   if (cb != null) {
     cb.clear();
   }
 }
 /** 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(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();
     }
   }
 }
 private void clearCachedEntries(String affectDNs) {
   Enumeration cacheKeys = sdkCache.keys();
   while (cacheKeys.hasMoreElements()) {
     String key = (String) cacheKeys.nextElement();
     int l1 = key.length();
     int l2 = affectDNs.length();
     if (key.regionMatches(true, (l1 - l2), affectDNs, 0, l2)) {
       // key ends with 'affectDN' string
       CacheBlock cb = (CacheBlock) sdkCache.get(key);
       if (cb != null) {
         cb.clear();
       }
     }
   }
 }
 // *************************************************************************
 // Update/Dirty methods of this class.
 // *************************************************************************
 private void removeCachedAttributes(String affectDNs, Set attrNames) {
   Enumeration cacheKeys = sdkCache.keys();
   while (cacheKeys.hasMoreElements()) {
     String key = (String) cacheKeys.nextElement();
     int l1 = key.length();
     int l2 = affectDNs.length();
     if (key.regionMatches(true, (l1 - l2), affectDNs, 0, l2)) {
       // key ends with 'affectDN' string
       CacheBlock cb = (CacheBlock) sdkCache.get(key);
       if (cb != null && !cb.hasExpiredAndUpdated() && cb.isExists()) {
         cb.removeAttributes(attrNames);
       }
     }
   }
 }
 /** Prints the contents of the cache. For getDebug() purpose only */
 public String toString() {
   StringBuffer sb = new StringBuffer();
   sb.append("\n<<<<<<< BEGIN SDK CACHE CONTENTS >>>>>>>>");
   if (!sdkCache.isEmpty()) { // Should never be null
     Enumeration cacheKeys = sdkCache.keys();
     while (cacheKeys.hasMoreElements()) {
       String key = (String) cacheKeys.nextElement();
       CacheBlock cb = (CacheBlock) sdkCache.get(key);
       sb.append("\nSDK Cache Block: ").append(key);
       sb.append(cb.toString());
     }
   } else {
     sb.append("<empty>");
   }
   sb.append("\n<<<<<<< END SDK CACHE CONTENTS >>>>>>>>");
   return sb.toString();
 }
 /**
  * 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;
 }
  /**
   * 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;
  }
 private void setOrganizationDNs(String organizationDN, Set childDNSet) {
   Iterator itr = childDNSet.iterator();
   while (itr.hasNext()) {
     String cDN = (String) itr.next();
     CacheBlock cb = (CacheBlock) sdkCache.get(cDN);
     if (cb == null) {
       cb = new CacheBlock(cDN, organizationDN, true);
       sdkCache.put(cDN, cb);
     } else {
       cb.setOrganizationDN(organizationDN);
     }
   }
   if (getDebug().messageEnabled() && !childDNSet.isEmpty()) {
     getDebug()
         .message(
             "CachedRemoteServicesImpl."
                 + "setOrganizationDNs(): Set org DNs as: "
                 + organizationDN
                 + " for children: "
                 + childDNSet);
   }
 }
 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;
  }
  /**
   * Gets the Organization DN for the specified entryDN. If the entry itself is an org, then same DN
   * is returned.
   *
   * <p><b>NOTE:</b> This method will involve serveral directory searches, hence be cautious of
   * Performance hit.
   *
   * <p>This method does not call its base classes method unlike the rest of the overriden methods
   * to obtain the organization DN, as it requires special processing requirements.
   *
   * @param token a valid SSOToken
   * @param entryDN the entry whose parent Organization is to be obtained
   * @return the DN String of the parent Organization
   * @throws AMException if an error occured while obtaining the parent Organization
   */
  public String getOrganizationDN(SSOToken token, String entryDN) throws AMException {
    DN dnObject = new DN(entryDN);
    if (entryDN.length() == 0 || !dnObject.isDN()) {
      getDebug().error("CachedRemoteServicesImpl.getOrganizationDN() " + "Invalid DN: " + entryDN);
      throw new AMException(token, "157");
    }

    String organizationDN = "";
    Set childDNSet = new HashSet();
    boolean errorCondition = false;
    boolean found = false;
    while (!errorCondition && !found) {
      boolean lookupDirectory = true;
      String childDN = dnObject.toRFCString().toLowerCase();
      if (getDebug().messageEnabled()) {
        getDebug()
            .message(
                "CachedRemoteServicesImpl."
                    + "getOrganizationDN() - looping Organization DN for"
                    + " entry: "
                    + childDN);
      }

      CacheBlock cb = (CacheBlock) sdkCache.get(childDN);
      if (cb != null) {
        organizationDN = cb.getOrganizationDN();
        if (organizationDN != null) {
          if (getDebug().messageEnabled()) {
            getDebug()
                .message(
                    "CachedRemoteServicesImpl."
                        + "getOrganizationDN(): found OrganizationDN: "
                        + organizationDN
                        + " for: "
                        + childDN);
          }
          found = true;
          setOrganizationDNs(organizationDN, childDNSet);
          continue;
        } else if (cb.getObjectType() == AMObject.ORGANIZATION
            || cb.getObjectType() == AMObject.ORGANIZATIONAL_UNIT) {
          // Object type is organization
          organizationDN = childDN;
          found = true;
          childDNSet.add(childDN);
          setOrganizationDNs(organizationDN, childDNSet);
          continue;
        } else if (cb.getObjectType() != AMObject.UNDETERMINED_OBJECT_TYPE) {
          // Don't lookup directory if the object type is unknown
          lookupDirectory = false;
        }
      }
      childDNSet.add(childDN);
      if (lookupDirectory) {
        organizationDN = super.verifyAndGetOrgDN(token, entryDN, childDN);
      }
      if (organizationDN != null && organizationDN.length() > 0) {
        found = true;
        setOrganizationDNs(organizationDN, childDNSet);
      } else if (dnObject.countRDNs() == 1) { // Reached topmost level
        errorCondition = true;
        getDebug()
            .error(
                "CachedRemoteServicesImpl."
                    + "getOrganizationDN(): Reached root suffix. Unable to"
                    + " get parent Org");
      } else { // Climb tree on level up
        dnObject = dnObject.getParent();
      }
    }
    return organizationDN;
  }
 /**
  * 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);
   }
 }