@SuppressWarnings("null")
  @Override
  protected void showInputForm(
      @Nonnull final WebPageExecutionContext aWPEC,
      @Nullable final IUser aSelectedObject,
      @Nonnull final HCForm aForm,
      final boolean bEdit,
      final boolean bCopy,
      @Nonnull final FormErrors aFormErrors) {
    if (bEdit && !isEditAllowed(aSelectedObject)) throw new IllegalStateException("Won't work!");

    final boolean bIsAdministrator = aSelectedObject != null && aSelectedObject.isAdministrator();
    final Locale aDisplayLocale = aWPEC.getDisplayLocale();
    final AccessManager aMgr = AccessManager.getInstance();
    final IHCTableForm<?> aTable =
        aForm.addAndReturnChild(
            getStyler().createTableForm(new HCCol(170), HCCol.star(), new HCCol(20)));
    aTable.setSpanningHeaderContent(
        bEdit
            ? EText.TITLE_EDIT.getDisplayTextWithArgs(
                aDisplayLocale, SecurityUI.getUserDisplayName(aSelectedObject, aDisplayLocale))
            : EText.TITLE_CREATE.getDisplayText(aDisplayLocale));

    if (!useEmailAddressAsLoginName()) {
      final String sLoginName = EText.LABEL_LOGINNAME.getDisplayText(aDisplayLocale);
      aTable
          .createItemRow()
          .setLabelMandatory(sLoginName)
          .setCtrl(
              new HCEdit(
                      new RequestField(
                          FIELD_LOGINNAME,
                          aSelectedObject == null ? null : aSelectedObject.getLoginName()))
                  .setPlaceholder(sLoginName))
          .setErrorList(aFormErrors.getListOfField(FIELD_LOGINNAME));
    }

    {
      final String sFirstName = EText.LABEL_FIRSTNAME.getDisplayText(aDisplayLocale);
      aTable
          .createItemRow()
          .setLabel(sFirstName)
          .setCtrl(
              new HCEdit(
                      new RequestField(
                          FIELD_FIRSTNAME,
                          aSelectedObject == null ? null : aSelectedObject.getFirstName()))
                  .setPlaceholder(sFirstName))
          .setErrorList(aFormErrors.getListOfField(FIELD_FIRSTNAME));
    }

    {
      final String sLastName = EText.LABEL_LASTNAME.getDisplayText(aDisplayLocale);
      aTable
          .createItemRow()
          .setLabel(sLastName, isLastNameMandatory() ? ELabelType.MANDATORY : ELabelType.OPTIONAL)
          .setCtrl(
              new HCEdit(
                      new RequestField(
                          FIELD_LASTNAME,
                          aSelectedObject == null ? null : aSelectedObject.getLastName()))
                  .setPlaceholder(sLastName))
          .setErrorList(aFormErrors.getListOfField(FIELD_LASTNAME));
    }

    {
      final String sEmail = EText.LABEL_EMAIL.getDisplayText(aDisplayLocale);
      aTable
          .createItemRow()
          .setLabel(sEmail, isEmailMandatory() ? ELabelType.MANDATORY : ELabelType.OPTIONAL)
          .setCtrl(
              new HCEdit(
                      new RequestField(
                          FIELD_EMAILADDRESS,
                          aSelectedObject == null ? null : aSelectedObject.getEmailAddress()))
                  .setPlaceholder(sEmail))
          .setErrorList(aFormErrors.getListOfField(FIELD_EMAILADDRESS));
    }

    if (!bEdit) {
      // Password is only shown on creation of a new user
      final boolean bHasAnyPasswordConstraint =
          GlobalPasswordSettings.getPasswordConstraintList().hasConstraints();

      final String sPassword = EText.LABEL_PASSWORD.getDisplayText(aDisplayLocale);
      aTable
          .createItemRow()
          .setLabel(
              sPassword, bHasAnyPasswordConstraint ? ELabelType.MANDATORY : ELabelType.OPTIONAL)
          .setCtrl(new HCEditPassword(FIELD_PASSWORD).setPlaceholder(sPassword))
          .setNote(SecurityUI.createPasswordConstraintTip(aDisplayLocale))
          .setErrorList(aFormErrors.getListOfField(FIELD_PASSWORD));

      final String sPasswordConfirm = EText.LABEL_PASSWORD_CONFIRM.getDisplayText(aDisplayLocale);
      aTable
          .createItemRow()
          .setLabel(
              sPasswordConfirm,
              bHasAnyPasswordConstraint ? ELabelType.MANDATORY : ELabelType.OPTIONAL)
          .setCtrl(new HCEditPassword(FIELD_PASSWORD_CONFIRM).setPlaceholder(sPasswordConfirm))
          .setNote(SecurityUI.createPasswordConstraintTip(aDisplayLocale))
          .setErrorList(aFormErrors.getListOfField(FIELD_PASSWORD_CONFIRM));
    }

    if (bIsAdministrator) {
      // Cannot edit enabled state of administrator
      aTable
          .createItemRow()
          .setLabel(EText.LABEL_ENABLED.getDisplayText(aDisplayLocale))
          .setCtrl(EWebBasicsText.getYesOrNo(aSelectedObject.isEnabled(), aDisplayLocale));
    } else {
      aTable
          .createItemRow()
          .setLabelMandatory(EText.LABEL_ENABLED.getDisplayText(aDisplayLocale))
          .setCtrl(
              new HCCheckBox(
                  new RequestFieldBoolean(
                      FIELD_ENABLED,
                      aSelectedObject == null ? DEFAULT_ENABLED : aSelectedObject.isEnabled())))
          .setErrorList(aFormErrors.getListOfField(FIELD_ENABLED));
    }

    {
      final Collection<String> aUserGroupIDs =
          aSelectedObject == null
              ? aWPEC.getAttrs(FIELD_USERGROUPS)
              : aMgr.getAllUserGroupIDsWithAssignedUser(aSelectedObject.getID());
      final UserGroupForUserSelect aSelect =
          new UserGroupForUserSelect(
              new RequestField(FIELD_USERGROUPS), aDisplayLocale, aUserGroupIDs);
      aTable
          .createItemRow()
          .setLabelMandatory(EText.LABEL_USERGROUPS_0.getDisplayText(aDisplayLocale))
          .setCtrl(aSelect)
          .setErrorList(aFormErrors.getListOfField(FIELD_USERGROUPS));
      if (bIsAdministrator) {
        // Cannot edit user groups of administrator
        aSelect.setReadonly(true);
      }
      showInputFormModifyUserGroupSelect(aSelect);
    }

    // Custom overridable
    showInputFormEnd(aWPEC, aSelectedObject, aForm, bEdit, bCopy, aFormErrors, aTable);
  }
  @Override
  protected boolean handleCustomActions(
      @Nonnull final WebPageExecutionContext aWPEC, @Nullable final IUser aSelectedObject) {
    if (aWPEC.hasAction(ACTION_RESET_PASSWORD) && aSelectedObject != null) {
      if (!canResetPassword(aSelectedObject)) throw new IllegalStateException("Won't work!");

      final Locale aDisplayLocale = aWPEC.getDisplayLocale();
      final boolean bShowForm = true;
      final FormErrors aFormErrors = new FormErrors();
      if (aWPEC.hasSubAction(ACTION_PERFORM)) {
        final String sPlainTextPassword = aWPEC.getAttr(FIELD_PASSWORD);
        final String sPlainTextPasswordConfirm = aWPEC.getAttr(FIELD_PASSWORD_CONFIRM);

        final List<String> aPasswordErrors =
            GlobalPasswordSettings.getPasswordConstraintList()
                .getInvalidPasswordDescriptions(sPlainTextPassword, aDisplayLocale);
        for (final String sPasswordError : aPasswordErrors)
          aFormErrors.addFieldError(FIELD_PASSWORD, sPasswordError);
        if (!EqualsUtils.equals(sPlainTextPassword, sPlainTextPasswordConfirm))
          aFormErrors.addFieldError(
              FIELD_PASSWORD_CONFIRM,
              EText.ERROR_PASSWORDS_DONT_MATCH.getDisplayText(aDisplayLocale));

        if (aFormErrors.isEmpty()) {
          AccessManager.getInstance().setUserPassword(aSelectedObject.getID(), sPlainTextPassword);
          aWPEC
              .getNodeList()
              .addChild(
                  getStyler()
                      .createSuccessBox(
                          EText.SUCCESS_RESET_PASSWORD.getDisplayTextWithArgs(
                              aDisplayLocale,
                              SecurityUI.getUserDisplayName(aSelectedObject, aDisplayLocale))));
          return true;
        }
      }
      if (bShowForm) {
        // Show input form
        final boolean bHasAnyPasswordConstraint =
            GlobalPasswordSettings.getPasswordConstraintList().hasConstraints();
        final HCForm aForm = aWPEC.getNodeList().addAndReturnChild(createFormSelf());
        final IHCTableForm<?> aTable =
            aForm.addAndReturnChild(
                getStyler().createTableForm(new HCCol(200), HCCol.star(), new HCCol(20)));
        aTable.setSpanningHeaderContent(
            EText.TITLE_RESET_PASSWORD.getDisplayTextWithArgs(
                aDisplayLocale, SecurityUI.getUserDisplayName(aSelectedObject, aDisplayLocale)));

        final String sPassword = EText.LABEL_PASSWORD.getDisplayText(aDisplayLocale);
        aTable
            .createItemRow()
            .setLabel(
                sPassword, bHasAnyPasswordConstraint ? ELabelType.MANDATORY : ELabelType.OPTIONAL)
            .setCtrl(new HCEditPassword(FIELD_PASSWORD).setPlaceholder(sPassword))
            .setNote(SecurityUI.createPasswordConstraintTip(aDisplayLocale))
            .setErrorList(aFormErrors.getListOfField(FIELD_PASSWORD));

        final String sPasswordConfirm = EText.LABEL_PASSWORD_CONFIRM.getDisplayText(aDisplayLocale);
        aTable
            .createItemRow()
            .setLabel(
                sPasswordConfirm,
                bHasAnyPasswordConstraint ? ELabelType.MANDATORY : ELabelType.OPTIONAL)
            .setCtrl(new HCEditPassword(FIELD_PASSWORD_CONFIRM).setPlaceholder(sPasswordConfirm))
            .setNote(SecurityUI.createPasswordConstraintTip(aDisplayLocale))
            .setErrorList(aFormErrors.getListOfField(FIELD_PASSWORD_CONFIRM));

        final IButtonToolbar<?> aToolbar = aForm.addAndReturnChild(getStyler().createToolbar());
        aToolbar.addHiddenField(CHCParam.PARAM_ACTION, ACTION_RESET_PASSWORD);
        aToolbar.addHiddenField(CHCParam.PARAM_OBJECT, aSelectedObject.getID());
        aToolbar.addHiddenField(CHCParam.PARAM_SUBACTION, ACTION_PERFORM);
        aToolbar.addSubmitButtonSave(aDisplayLocale);
        aToolbar.addButtonCancel(aDisplayLocale);
      }
      return false;
    }
    return true;
  }
  @Override
  @SuppressWarnings("null")
  protected void validateAndSaveInputParameters(
      @Nonnull final WebPageExecutionContext aWPEC,
      @Nullable final IUser aSelectedObject,
      @Nonnull final FormErrors aFormErrors,
      final boolean bEdit) {
    final HCNodeList aNodeList = aWPEC.getNodeList();
    final Locale aDisplayLocale = aWPEC.getDisplayLocale();
    final boolean bIsAdministrator = aSelectedObject != null && aSelectedObject.isAdministrator();
    final AccessManager aAccessMgr = AccessManager.getInstance();
    String sLoginName = aWPEC.getAttr(FIELD_LOGINNAME);
    final String sFirstName = aWPEC.getAttr(FIELD_FIRSTNAME);
    final String sLastName = aWPEC.getAttr(FIELD_LASTNAME);
    final String sEmailAddress = aWPEC.getAttr(FIELD_EMAILADDRESS);
    final String sPassword = aWPEC.getAttr(FIELD_PASSWORD);
    final String sPasswordConf = aWPEC.getAttr(FIELD_PASSWORD_CONFIRM);
    final boolean bEnabled =
        bIsAdministrator ? true : aWPEC.getCheckBoxAttr(FIELD_ENABLED, DEFAULT_ENABLED);
    final Collection<String> aUserGroupIDs =
        bIsAdministrator
            ? aAccessMgr.getAllUserGroupIDsWithAssignedUser(aSelectedObject.getID())
            : aWPEC.getAttrs(FIELD_USERGROUPS);

    if (useEmailAddressAsLoginName()) {
      sLoginName = sEmailAddress;
    } else {
      if (StringHelper.hasNoText(sLoginName))
        aFormErrors.addFieldError(
            FIELD_LOGINNAME, EText.ERROR_LOGINNAME_REQUIRED.getDisplayText(aDisplayLocale));
    }

    if (StringHelper.hasNoText(sLastName)) {
      if (isLastNameMandatory())
        aFormErrors.addFieldError(
            FIELD_LASTNAME, EText.ERROR_LASTNAME_REQUIRED.getDisplayText(aDisplayLocale));
    }

    if (StringHelper.hasNoText(sEmailAddress)) {
      if (isEmailMandatory())
        aFormErrors.addFieldError(
            FIELD_EMAILADDRESS, EText.ERROR_EMAIL_REQUIRED.getDisplayText(aDisplayLocale));
    } else if (!EmailAddressUtils.isValid(sEmailAddress))
      aFormErrors.addFieldError(
          FIELD_EMAILADDRESS, EText.ERROR_EMAIL_INVALID.getDisplayText(aDisplayLocale));
    else {
      final IUser aSameLoginUser = aAccessMgr.getUserOfLoginName(sEmailAddress);
      if (aSameLoginUser != null)
        if (!bEdit || !aSameLoginUser.equals(aSelectedObject))
          aFormErrors.addFieldError(
              FIELD_EMAILADDRESS, EText.ERROR_EMAIL_IN_USE.getDisplayText(aDisplayLocale));
    }

    if (!bEdit) {
      final List<String> aPasswordErrors =
          GlobalPasswordSettings.getPasswordConstraintList()
              .getInvalidPasswordDescriptions(sPassword, aDisplayLocale);
      for (final String sPasswordError : aPasswordErrors)
        aFormErrors.addFieldError(FIELD_PASSWORD, sPasswordError);
      if (!EqualsUtils.equals(sPassword, sPasswordConf))
        aFormErrors.addFieldError(
            FIELD_PASSWORD_CONFIRM,
            EText.ERROR_PASSWORDS_DONT_MATCH.getDisplayText(aDisplayLocale));
    }

    if (ContainerHelper.isEmpty(aUserGroupIDs))
      aFormErrors.addFieldError(
          FIELD_USERGROUPS, EText.ERROR_NO_USERGROUP.getDisplayText(aDisplayLocale));
    else if (!aAccessMgr.containsAllUserGroupsWithID(aUserGroupIDs))
      aFormErrors.addFieldError(
          FIELD_USERGROUPS, EText.ERROR_INVALID_USERGROUPS.getDisplayText(aDisplayLocale));

    // Call custom method
    final Map<String, String> aCustomAttrMap =
        validateCustomParameters(aWPEC, aSelectedObject, aFormErrors, bEdit);

    if (aFormErrors.isEmpty()) {
      // All fields are valid -> save
      if (bEdit) {
        final String sUserID = aSelectedObject.getID();

        final Map<String, Object> aAttrMap = aSelectedObject.getAllAttributes();
        if (aCustomAttrMap != null) aAttrMap.putAll(aCustomAttrMap);

        // We're editing an existing object
        aAccessMgr.setUserData(
            sUserID,
            sLoginName,
            sEmailAddress,
            sFirstName,
            sLastName,
            m_aDefaultUserLocale,
            aAttrMap,
            !bEnabled);
        aNodeList.addChild(
            getStyler().createSuccessBox(EText.SUCCESS_EDIT.getDisplayText(aDisplayLocale)));

        // assign to the matching user groups
        final Collection<String> aPrevUserGroupIDs =
            aAccessMgr.getAllUserGroupIDsWithAssignedUser(sUserID);
        // Create all missing assignments
        final Set<String> aUserGroupsToBeAssigned =
            ContainerHelper.getDifference(aUserGroupIDs, aPrevUserGroupIDs);
        for (final String sUserGroupID : aUserGroupsToBeAssigned)
          aAccessMgr.assignUserToUserGroup(sUserGroupID, sUserID);

        // Delete all old assignments
        final Set<String> aUserGroupsToBeUnassigned =
            ContainerHelper.getDifference(aPrevUserGroupIDs, aUserGroupIDs);
        for (final String sUserGroupID : aUserGroupsToBeUnassigned)
          aAccessMgr.unassignUserFromUserGroup(sUserGroupID, sUserID);

      } else {
        // We're creating a new object
        final IUser aNewUser =
            aAccessMgr.createNewUser(
                sLoginName,
                sEmailAddress,
                sPassword,
                sFirstName,
                sLastName,
                m_aDefaultUserLocale,
                aCustomAttrMap,
                !bEnabled);
        if (aNewUser != null) {
          aNodeList.addChild(
              getStyler().createSuccessBox(EText.SUCCESS_CREATE.getDisplayText(aDisplayLocale)));

          // assign to the matching internal user groups
          for (final String sUserGroupID : aUserGroupIDs)
            aAccessMgr.assignUserToUserGroup(sUserGroupID, aNewUser.getID());
        } else
          aNodeList.addChild(
              getStyler().createErrorBox(EText.FAILURE_CREATE.getDisplayText(aDisplayLocale)));
      }
    }
  }