/**
   * add a multi assignable attribute
   *
   * @param action is the action on the assignment (null means default action)
   * @param attributeDefName
   * @param checkSecurity
   * @param uuid uuid of the assignment
   * @return the result including if added or already there
   */
  public AttributeAssignResult internal_addAttributeHelper(
      String action, AttributeDefName attributeDefName, boolean checkSecurity, String uuid) {

    AttributeDef attributeDef = attributeDefName.getAttributeDef();
    if (!attributeDef.isMultiAssignable()) {
      throw new RuntimeException(
          "This attribute must be multi-assignable to call this method, use the non multi-assign method: "
              + attributeDefName.getName());
    }

    if (checkSecurity) {
      this.assertCanUpdateAttributeDefName(attributeDefName);
    }

    this.assertScopeOk(attributeDef);

    AttributeAssign attributeAssign = newAttributeAssign(action, attributeDefName, uuid);

    if (StringUtils.isBlank(attributeAssign.getAttributeAssignActionId())) {
      attributeAssign.setAttributeAssignActionId(
          attributeDef.getAttributeDefActionDelegate().allowedAction(action, true).getId());
    }

    attributeAssign.saveOrUpdate(checkSecurity);

    return new AttributeAssignResult(true, attributeAssign);
  }
  /**
   * @param action is the action on the assignment (null means default action)
   * @param attributeDefName
   * @param assign true to assign, false to unassign
   * @param attributeAssignDelegateOptions if there are more options, null if not
   * @return the result including if added or already there
   */
  public AttributeAssignResult delegateAttribute(
      final String action,
      final AttributeDefName attributeDefName,
      final boolean assign,
      final AttributeAssignDelegateOptions attributeAssignDelegateOptions) {

    AttributeDef attributeDef = attributeDefName.getAttributeDef();

    if (attributeDef.isMultiAssignable()) {
      throw new RuntimeException(
          "This attribute must not be multi-assignable to call "
              + "this method, use the multi-assign methods: "
              + attributeDefName.getName());
    }

    this.assertCanDelegateAttributeDefName(action, attributeDefName);

    if (attributeAssignDelegateOptions != null
        && attributeAssignDelegateOptions.isAssignAttributeAssignDelegatable()) {
      if (attributeAssignDelegateOptions.getAttributeAssignDelegatable()
              == AttributeAssignDelegatable.GRANT
          || attributeAssignDelegateOptions.getAttributeAssignDelegatable()
              == AttributeAssignDelegatable.TRUE) {
        this.assertCanGrantAttributeDefName(action, attributeDefName);
      }
    }

    AttributeAssignResult attributeAssignResult =
        (AttributeAssignResult)
            GrouperSession.callbackGrouperSession(
                GrouperSession.staticGrouperSession().internal_getRootSession(),
                new GrouperSessionHandler() {

                  public Object callback(GrouperSession grouperSession)
                      throws GrouperSessionException {

                    if (assign) {

                      // do the same thing that an assign would do
                      // do this as root since the user who can delegate might not be able to
                      // assign...
                      AttributeAssignResult attributeAssignResult2 =
                          AttributeAssignBaseDelegate.this.internal_assignAttributeHelper(
                              action, attributeDefName, false, null, null);

                      if (attributeAssignDelegateOptions != null) {

                        AttributeAssign attributeAssign =
                            attributeAssignResult2.getAttributeAssign();
                        if (attributeAssignDelegateOptions.isAssignAttributeAssignDelegatable()) {
                          attributeAssign.setAttributeAssignDelegatable(
                              attributeAssignDelegateOptions.getAttributeAssignDelegatable());
                        }
                        if (attributeAssignDelegateOptions.isAssignDisabledDate()) {
                          attributeAssign.setDisabledTime(
                              attributeAssignDelegateOptions.getDisabledTime());
                        }
                        if (attributeAssignDelegateOptions.isAssignEnabledDate()) {
                          attributeAssign.setDisabledTime(
                              attributeAssignDelegateOptions.getEnabledTime());
                        }
                        attributeAssign.saveOrUpdate(true);
                      }
                      return attributeAssignResult2;
                    }

                    return AttributeAssignBaseDelegate.this.removeAttributeHelper(
                        action, attributeDefName, false);
                  }
                });

    return attributeAssignResult;
  }
  /**
   * @param action is the action on the assignment (null means default action)
   * @param attributeDefName
   * @param checkSecurity
   * @param uuid uuid of the assignment
   * @param permissionAllowed if permission this is the allowed flag
   * @return the result including if added or already there
   */
  public AttributeAssignResult internal_assignAttributeHelper(
      String action,
      AttributeDefName attributeDefName,
      boolean checkSecurity,
      String uuid,
      PermissionAllowed permissionAllowed) {

    if (permissionAllowed == null) {
      permissionAllowed = PermissionAllowed.ALLOWED;
    }

    AttributeDef attributeDef = attributeDefName.getAttributeDef();

    if (checkSecurity) {
      this.assertCanUpdateAttributeDefName(attributeDefName);
    }

    boolean isPermission =
        AttributeDefType.perm.equals(attributeDefName.getAttributeDef().getAttributeDefType());
    if (permissionAllowed != null && permissionAllowed.isDisallowed() && !isPermission) {
      throw new RuntimeException(
          "Can only assign a permissionAllowed with attributeDefName as perm (permission) type: "
              + attributeDefName.getName()
              + ", "
              + attributeDefName.getAttributeDef().getAttributeDefType());
    }

    AttributeAssign attributeAssign = retrieveAssignment(action, attributeDefName, false, false);

    if (attributeAssign != null) {
      if (permissionAllowed != null
          && permissionAllowed.isDisallowed() != attributeAssign.isDisallowed()) {
        throw new RuntimeException(
            "Assigning disallowed: "
                + permissionAllowed.isDisallowed()
                + ", but the existing assignment "
                + attributeAssign.getId()
                + " has: "
                + attributeAssign.isDisallowed()
                + ", you need to delete assignment and reassign.");
      }
      return new AttributeAssignResult(false, attributeAssign);
    }

    attributeAssign = newAttributeAssign(action, attributeDefName, uuid);

    attributeAssign.setDisallowed(
        permissionAllowed == null ? false : permissionAllowed.isDisallowed());

    if (StringUtils.isBlank(attributeAssign.getAttributeAssignActionId())) {
      attributeAssign.setAttributeAssignActionId(
          attributeDef.getAttributeDefActionDelegate().allowedAction(action, true).getId());
    }

    this.assertScopeOk(attributeDef);

    attributeAssign.internalSetAttributeDef(attributeDef);
    attributeAssign.internalSetAttributeDefName(attributeDefName);
    attributeAssign.saveOrUpdate(checkSecurity);
    return new AttributeAssignResult(true, attributeAssign);
  }