/**
   * resolve attribute created-by.
   *
   * @param ctx EvaluationContext
   * @param attributeIdValue whole attribute
   * @param resolvableAttribute resolvable part of attribute
   * @param tail tail after resolvable part
   * @return Object[] result
   * @throws de.escidoc.core.common.exceptions.system.WebserverSystemException
   * @throws de.escidoc.core.common.exceptions.system.SqlDatabaseSystemException
   * @throws de.escidoc.core.common.exceptions.application.notfound.GrantNotFoundException
   * @throws de.escidoc.core.common.exceptions.application.notfound.ResourceNotFoundException
   */
  private Object[] resolveCreatedByAttribute(
      final EvaluationCtx ctx,
      final String attributeIdValue,
      final String resolvableAttribute,
      final String tail)
      throws GrantNotFoundException, SqlDatabaseSystemException, ResourceNotFoundException,
          WebserverSystemException {
    final String userOrGroupId =
        FinderModuleHelper.retrieveSingleResourceAttribute(ctx, Constants.URI_RESOURCE_ID, true);
    final String grantId =
        FinderModuleHelper.retrieveSingleResourceAttribute(ctx, Constants.URI_SUBRESOURCE_ID, true);
    if (grantId == null || grantId.length() == 0) {
      throw new GrantNotFoundException("no grantId found");
    }
    final RoleGrant grant =
        resolvableAttribute.matches(".*" + XmlUtility.NAME_USER_ACCOUNT + ".*")
            ? userAccountDao.retrieveGrant(userOrGroupId, grantId)
            : userGroupDao.retrieveGrant(grantId);
    assertGrant(grantId, grant);
    final String createdBy = grant.getCreatorId();

    final EvaluationResult result =
        CustomEvaluationResultBuilder.createSingleStringValueResult(createdBy);
    return new Object[] {result, resolvableAttribute};
  }
  /**
   * Fetches the scopes of the role identified in the attribute for the provided user account.
   *
   * @param userAccountId The id of the user account to fetch the value from.
   * @param attributeId The name of the attribute.
   * @return Returns the attribute value in an {@code EvaluationResult}.
   * @throws de.escidoc.core.common.exceptions.system.SystemException
   */
  private EvaluationResult fetchRoleScopes(
      final String userAccountId, final CharSequence attributeId) throws SystemException {

    // get role to fetch
    final Matcher roleMatcher = PATTERN_PARSE_ROLE_GRANT_ROLE.matcher(attributeId);
    String roleName = null;
    if (roleMatcher.find()) {
      roleName = roleMatcher.group(4);
    }
    if (roleName == null || roleName.length() == 0) {
      return CustomEvaluationResultBuilder.createEmptyEvaluationResult();
    }

    Set<String> userGroups = null;
    try {
      userGroups = securityHelper.getUserGroups(userAccountId);
    } catch (UserAccountNotFoundException e) {
      // The caller doesn't expect to get an exception from here if
      // the user doesn't exist.
    }
    final Map<String, HashSet<String>> criterias = new HashMap<String, HashSet<String>>();
    final HashSet<String> roles = new HashSet<String>();
    roles.add(roleName);
    final HashSet<String> users = new HashSet<String>();
    users.add(userAccountId);
    criterias.put(de.escidoc.core.common.business.Constants.FILTER_PATH_USER_ID, users);
    criterias.put(de.escidoc.core.common.business.Constants.FILTER_PATH_ROLE_ID, roles);
    if (userGroups != null && !userGroups.isEmpty()) {
      criterias.put(
          de.escidoc.core.common.business.Constants.FILTER_PATH_GROUP_ID,
          (HashSet<String>) userGroups);
    }
    final List<RoleGrant> roleGrants =
        userAccountDao.retrieveGrants(criterias, null, ListSorting.ASCENDING);
    final EvaluationResult result;
    if (roleGrants != null) {
      final List<StringAttribute> results = new ArrayList<StringAttribute>();
      for (final RoleGrant roleGrant : roleGrants) {
        if (roleGrant.getRevocationDate() == null) {
          results.add(new StringAttribute(roleGrant.getObjectId()));
        }
      }
      result = new EvaluationResult(new BagAttribute(Constants.URI_XMLSCHEMA_STRING, results));
    } else {
      result = CustomEvaluationResultBuilder.createEmptyEvaluationResult();
    }
    return result;
  }
  /**
   * Retrieve user-account grant from the system.
   *
   * @param ctx The evaluation context, which will be used as key for the cache.
   * @param userId The user id.
   * @param grantId The grant id.
   * @return Returns the {@code RoleGrant} identified by the provided id.
   * @throws WebserverSystemException Thrown in case of an internal error.
   * @throws GrantNotFoundException Thrown if no grant with provided id exists.
   */
  private RoleGrant getUserAccountGrant(
      final EvaluationCtx ctx, final String userId, final String grantId)
      throws WebserverSystemException, GrantNotFoundException {
    RoleGrant grant = (RoleGrant) getFromCache(XmlUtility.NAME_ID, null, null, grantId, ctx);
    if (grant == null) {
      try {
        grant = userAccountDao.retrieveGrant(userId, grantId);
      } catch (final Exception e) {
        throw new WebserverSystemException(
            StringUtility.format("Exception during retrieval of the grant", e.getMessage()), e);
      }
    }
    assertGrant(grantId, grant);

    putInCache(XmlUtility.NAME_ID, null, null, grantId, ctx, grant);
    return grant;
  }
  /**
   * Retrieve user-account grant from the system.
   *
   * @param ctx The evaluation context, which will be used as key for the cache.
   * @param userId The user id.
   * @param grantId The grant id.
   * @return Returns the <code>RoleGrant</code> identified by the provided id.
   * @throws WebserverSystemException Thrown in case of an internal error.
   * @throws GrantNotFoundException Thrown if no grant with provided id exists.
   */
  private RoleGrant getUserAccountGrant(
      final EvaluationCtx ctx, final String userId, final String grantId)
      throws WebserverSystemException, GrantNotFoundException {
    final StringBuffer key = StringUtility.concatenateWithColon(XmlUtility.NAME_ID, grantId);
    RoleGrant grant = (RoleGrant) RequestAttributesCache.get(ctx, key.toString());
    if (grant == null) {
      try {
        grant = userAccountDao.retrieveGrant(userId, grantId);
      } catch (final Exception e) {
        throw new WebserverSystemException(
            StringUtility.format("Exception during retrieval of the grant", e.getMessage()), e);
      }
    }
    assertGrant(grantId, grant);

    RequestAttributesCache.put(ctx, key.toString(), grant);
    return grant;
  }
  /**
   * Fetches the value of the attribute {@code ATTR_USER_OU} for the provided user account.
   *
   * @param userAccount The user account to fetch the value from.
   * @param getChildren if also children of userAccountous are to be fetched.
   * @return Returns the attribute value in an {@code EvaluationResult}.
   * @throws de.escidoc.core.common.exceptions.system.SystemException
   */
  private EvaluationResult fetchUserAccountOus(
      final UserAccount userAccount, final boolean getChildren) throws SystemException {

    final String ouAttributeName =
        EscidocConfiguration.getInstance()
            .get(EscidocConfiguration.ESCIDOC_CORE_AA_OU_ATTRIBUTE_NAME);
    if (ouAttributeName == null || ouAttributeName.length() == 0) {
      return CustomEvaluationResultBuilder.createEmptyEvaluationResult();
    }
    final List<UserAttribute> attributes =
        userAccountDao.retrieveAttributes(userAccount, ouAttributeName);
    final EvaluationResult result;
    if (attributes == null || attributes.isEmpty()) {
      result = CustomEvaluationResultBuilder.createEmptyEvaluationResult();
    } else {
      final List<StringAttribute> results = new ArrayList<StringAttribute>();
      final Collection<String> ouIds = new ArrayList<String>();
      for (final UserAttribute attribute : attributes) {
        results.add(new StringAttribute(attribute.getValue()));
        if (getChildren) {
          ouIds.add(attribute.getValue());
        }
      }
      if (getChildren) {
        final List<String> childOus =
            tripleStoreUtility.getChildrenPath(ouIds, new ArrayList<String>());
        if (childOus != null) {
          for (final String childOu : childOus) {
            results.add(new StringAttribute(childOu));
          }
        }
      }

      result = new EvaluationResult(new BagAttribute(Constants.URI_XMLSCHEMA_STRING, results));
    }
    return result;
  }