OsUsersPresenter.java

/*
** Module   : OsUsersPresenter.java
** Abstract : OsUsersPresenter implements common business methods to manage OS user accounts.
**
** Copyright (c) 2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- ----------------Description----------------------
** 001 GBB 20230807 Created initial version.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/
package com.goldencode.p2j.admin.client.application.home.accounts.osusers;

import com.goldencode.p2j.admin.*;
import com.goldencode.p2j.admin.client.*;
import com.goldencode.p2j.admin.client.application.*;
import com.goldencode.p2j.admin.client.application.home.*;
import com.goldencode.p2j.admin.client.application.home.accounts.*;
import com.goldencode.p2j.admin.client.application.home.acl.*;
import com.goldencode.p2j.admin.client.widget.dialog.*;
import com.goldencode.p2j.admin.shared.*;
import com.google.gwt.user.client.rpc.*;
import com.google.gwt.user.client.ui.*;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.web.bindery.event.shared.*;
import com.gwtplatform.mvp.client.*;
import com.gwtplatform.mvp.client.annotations.*;
import com.gwtplatform.mvp.client.presenter.slots.*;
import com.gwtplatform.mvp.client.proxy.*;

import javax.inject.*;
import java.util.*;
import java.util.logging.*;

/** OsUsersPresenter implements common business methods to manage OS user accounts. */
public class OsUsersPresenter
extends AccountsPresenter<OsUsersPresenter.MyView, OsUsersPresenter.MyProxy>
implements OsUsersUIHandlers
{
   /**
    * Defines user accounts view states.
    */
   private enum OsUsersViewStates
   implements ViewStateMachine.TransitionState
   {
      /** Users list has been refreshed. */
      USERS_LIST_REFRESHED(MASK_WEST_CENTER, STATE_INITIAL_EMPTY),
      
      /** The user account has been added currently. */
      ADD_USER_ACCOUNT(MASK_WEST_CENTER, STATE_USER_ADD),
      
      /** The user account has been edited currently. */
      EDIT_USER_ACCOUNT(MASK_WEST_CENTER, STATE_USER_EDIT),
      
      /** The single user has been selected currently. */
      SINGLE_USER_SELECTED(MASK_WEST_CENTER, STATE_USERS_SINGLE),
      
      /** The multiple users have been selected currently. */
      MULTI_USERS_SELECTED(MASK_WEST_CENTER, STATE_USERS_MULTI);
      
      /** The current components states to be enabled or disabled */
      private final boolean[] state;
      
      /** The current mask that defines components to which the current state is applied */
      private final boolean[] mask;
      
      /**
       * Creates a target view state.
       * 
       * @param    mask
       *           The current mask
       * @param    state
       *           The current state
       */
      OsUsersViewStates(boolean[] mask, boolean[] state)
      {
         this.mask  = mask;
         this.state = state;
      }
      
      /**
       * Gets the current state that defines the affected components states.
       * 
       * @return   The current state
       */
      @Override
      public boolean[] getState()
      {
         return this.state;
      }

      /**
       * Gets the current mask that defines the set of affected components (widgets).
       * 
       * @return   The current mask
       */
      @Override
      public boolean[] getMask()
      {
         return mask;
      }
   }
   
   /** state definition - initial empty */
   private static final boolean[] STATE_INITIAL_EMPTY =
   {
      /*       refresh               */ true,
      /*       addOsUserAccount      */ true,
      /*       deleteOsUserAccount   */ false,
      /*       editOsUserAccount     */ false,
      /*       disableOsUserAccount  */ false,
      /*       findOsUser            */ true
   };
   
   /** state definition - group definition creation */
   private static final boolean[] STATE_USER_ADD =
   {
      /*       refresh               */ false,
      /*       addOsUserAccount      */ false,
      /*       deleteOsUserAccount   */ false,
      /*       editOsUserAccount     */ false,
      /*       disableOsUserAccount  */ false,
      /*       findOsUser            */ false
   };

   /** state definition - group definition editing */
   private static final boolean[] STATE_USER_EDIT =
   {
      /*       refresh               */ false,
      /*       addOsUserAccount      */ false,
      /*       deleteOsUserAccount   */ false,
      /*       editOsUserAccount     */ false,
      /*       disableOsUserAccount  */ false,
      /*       findOsUser            */ false
   };

   /** state definition - single selection in users list */
   private static final boolean[] STATE_USERS_SINGLE =
   {
      /*       refresh               */ true,
      /*       addOsUserAccount      */ true,
      /*       deleteOsUserAccount   */ true,
      /*       editOsUserAccount     */ true,
      /*       disableOsUserAccount  */ true,
      /*       findOsUser            */ true
   };
   
   /** state definition - multiple selection in users list */
   private static final boolean[] STATE_USERS_MULTI =
   {
      /*       refresh               */ true,
      /*       addOsUserAccount      */ true,
      /*       deleteOsUserAccount   */ true,
      /*       editOsUserAccount     */ false,
      /*       disableOsUserAccount  */ false,
      /*       findOsUser            */ true
   };
   
   /** mask definition - west-center */
   private static final boolean[] MASK_WEST_CENTER =
   {
      /*       refresh               */ true,
      /*       addOsUserAccount      */ true,
      /*       deleteOsUserAccount   */ true,
      /*       editOsUserAccount     */ true,
      /*       disableOsUserAccount  */ true,
      /*       findOsUser            */ true
   };

   /** The attachment point for modal dialogs on this view*/
   public static final NestedSlot MODAL_CONTENT = new NestedSlot();
   
   /** Administration server interface */
   private final AdminServiceAsync adminService;
   
   /** The common modal dialogs manager */
   private final ModalDialogs modalDialogsManager;
   
   /** The server alarms manager */
   private final Alarm serverAlarmsManager;
   
   /** The currently selected user */
   private OsUserDef selectedUser;
   
   /** The set of selected users */
   private final Set<OsUserDef> selectedUsers;
   
   /** The user account definition provider */
   private final Provider<AddEditOsUserWidget> uadProvider;
   
   /** The common input dialogs provider */
   private final Provider<InputDialog> inputDialogProvider;

   /** The Find OS User Account manager */
   private final FindOsUserAccount findOsUserAccountManager;
   
   /**
    * This view interface that must be implemented by the concrete view according to GWTP
    * framework. Defines the exposed business methods.
    */
   public interface MyView
   extends View, HasUiHandlers<OsUsersUIHandlers>, Provider<HasEnabled[]>, PrintingContext
   {
      /**
       * Sets the all users table's model with users accounts data given by tagged names
       * 
       * @param    users
       *           The array of users accounts given by tagged names
       */
      void setUsers(TaggedName[] users);
      
      /**
       * Tests if these tested users have been selected from the all users table.
       * 
       * @param    users
       *           The array of tested user accounts given by tagged names
       * 
       * @return   True if all tested users have been selected, otherwise false.
       */
      boolean isSelectedFromUsers(TaggedName[] users);
      
      /**
       * Selects the user's data row from the all users table by a given user's tagged name.
       * 
       * @param    user
       *           The user account given by its tagged name
       */
      void selectUser(TaggedName user);
      
      /**
       * Selects the user's data row from the all users table by a given user's account name.
       * 
       * @param    name
       *           The account name.
       */
      void selectUserByName(String name);
      
      /**
       * Toggles the Disable/Enable User button's label.
       * 
       * @param    enabled
       *           Indicates the user's enabled state. The true value switches this button's label
       *           from "Enable User" to "Disable User" and vice versa the false value switches
       *           from "Disable User" to "Enable User".
       */
      void toggleDisableUserButton(boolean enabled);
      
      /**
       * Gets a reference to the Deleting Users Alert.
       * 
       * @return   The Deleting Users Alert
       */
      DeletingOsUsersAlert getDeletingUsersAlert();

      /**
       * Returns the parent container where the Add/Edit User Definition View will be revealed in.
       * 
       * @return   The parent container for the Add/Edit User Definition View.
       */
      HasWidgets getOsUserDefModalParent();
      
      /**
       * Sets the FWD users table's model with all associated FWD users for the single selected OS user 
       * from the OS users table view.
       *
       * @param    fwdUsers
       *           The array of FWD users given by tagged names
       */
      void setAssociatedFwdUsers(TaggedName[] fwdUsers);
   }

   /**
    * Defines the proxy place for GWTP framework. Binds /accounts/os-users url to this presenter.
    */
   @ProxyStandard
   @NameToken(NameTokens.OS_USERS)
   public interface MyProxy
   extends ProxyPlace<OsUsersPresenter>
   {}
   
   /**
    * Defines the Users presenter.
    * 
    * @param    eventBus
    *           The event bus
    * @param    view
    *           The associated view
    * @param    proxy
    *           The proxy place
    * @param    placeManager
    *           The place manager
    * @param    viewStateMachine
    *           The view state machine
    * @param    adminService
    *           The administration service
    * @param    modalDialogsManager
    *           The common modal dialogs manager
    * @param    serverAlarmsManager
    *           The server alarms
    * @param    uadProvider
    *           The user account definition provider
    * @param    inputDialogProvider
    *           InputDialog provider
    * @param    acctExtensionHolder
    *           The account extension holder
    * @param    aclPopupPresenterProvider
    *           The ACL popup presenter provider
    */
   @Inject
   public OsUsersPresenter(EventBus eventBus,
                           MyView view,
                           MyProxy proxy,
                           PlaceManager placeManager,
                           @Named("OsUsersViewStateMachine") ViewStateMachine viewStateMachine,
                           AdminServiceAsync adminService,
                           ModalDialogs modalDialogsManager,
                           Alarm serverAlarmsManager,
                           Provider<AddEditOsUserWidget> uadProvider,
                           Provider<InputDialog> inputDialogProvider,
                           AccountExtensionHolder acctExtensionHolder,
                           ACLPopupPresenter aclPopupPresenterProvider)
   {
      super(eventBus,
            view,
            proxy,
            HomePresenter.SLOT_CONTENT,
            placeManager,
            viewStateMachine,
            aclPopupPresenterProvider);

      this.adminService = adminService;
      this.modalDialogsManager = modalDialogsManager;
      this.serverAlarmsManager = serverAlarmsManager;
      this.uadProvider = uadProvider;
      this.inputDialogProvider = inputDialogProvider;
      this.findOsUserAccountManager = new FindOsUserAccount(acctExtensionHolder);
      this.selectedUsers = new HashSet<>();
      getView().setUiHandlers(this);
   }
   
   /**
    * Lifecycle method called on all visible presenters whenever a
    * presenter is revealed anywhere in the presenter hierarchy.
    * <p>
    * <b>Important:</b> Make sure you call your superclass {@link #onReset()} if
    * you override. Also, do not call directly, fire a
    * {@link com.gwtplatform.mvp.client.proxy.ResetPresentersEvent} to perform a reset manually.
    * See {@link com.gwtplatform.mvp.client.PresenterWidget} for more details on lifecycle
    * methods.
    * <p>
    * This is one of the most frequently used lifecycle method. This is usually a good
    * place to refresh any information displayed by your presenter.
    * <p>
    * Note that {@link #onReset()} is not called only when using
    * {@link #addToSlot(Object, PresenterWidget)}, {@link #addToPopupSlot(PresenterWidget)}
    * or {@link #setInSlot(Object, PresenterWidget, boolean)} with {@code false} as the third
    * parameter.
    * <p>
    * In a presenter hierarchy, this method is called top-down: first on the
    * parent presenters, then on the children.
    */
   @Override
   protected void onReset()
   {
      super.onReset();
      updateUsersList();
      setState(OsUsersViewStates.USERS_LIST_REFRESHED);
   }

   /**
    * Triggers an action to refresh the all users table.
    */
   @Override
   public void onRefresh()
   {
      updateUsersList();
      changeState(OsUsersViewStates.USERS_LIST_REFRESHED);
   }
   
   /**
    * Retrieves the user list and fills the all users table model.
    */
   private void updateUsersList()
   {
      updateUsersList(()->{});
   }
   
   /**
    * Retrieves the user list and fills the all users table model and executes a given command on
    * getting the user list.
    * 
    * @param    callback
    *           The given command to execute on getting the data
    */
   private void updateUsersList(Runnable callback)
   {
      this.adminService.listOsUsers(new AsyncCallback<TaggedName[]>()
      {
         @Override
         public void onSuccess(TaggedName[] result)
         {
            getView().setUsers(result);
            callback.run();
         }
         
         @Override
         public void onFailure(Throwable caught)
         {
            logger.log(Level.INFO, "Can't get all OS Users", caught);
            callback.run();
         }
      });
   }

   /**
    * Shows the Add OS User Account Dialog.
    */
   @Override
   public void showAddUserAccountDialog()
   {
      logger.log(Level.INFO, "showAddOsUserAccountDialog");
      AddEditOsUserWidget uad = uadProvider.get();
      uad.build(null, r ->
      {
         if (!r)
         {
            return;
         }

         uad.show(getView().getOsUserDefModalParent(), new OsUserDef(), userDef ->
         {
            if (userDef == null)
            {
               return;
            }

            addUser(userDef);
            updateUsersList();
         });
      });
   }

   /**
    * Setups the Deleting Users Alert.
    * 
    * @param    users
    *           The array of users accounts given by tagged names
    */
   @Override
   public void setupDeletingUsersAlert(TaggedName[] users)
   {
      logger.log(Level.INFO, "setupDeletingUsersAlert");
      
      if (users == null || users.length == 0)
      {
         return;
      }
      
      checkAssociatedFwdUsers(users, 0);
   }
   
   /**
    * Checks if the selected OS users are associated with FWD accounts. If any mapping found, a warning 
    * message is displayed to notify the delete action will not be executed. If no mapping is found, the 
    * search continues with the next user in the array. If no mappings are found up to the last user, a 
    * confirmation alert is displayed.
    *
    * @param    osUsers
    *           The array of OS users to be checked
    * @param    currentIndex
    *           The index of the current element in the array of OS users. Used for recursion.
    */
   private void checkAssociatedFwdUsers(TaggedName[] osUsers, int currentIndex)
   {
      String fwdUserId = osUsers[currentIndex].getName();
      adminService.listAssociatedFwdUsers(fwdUserId,
                                          new AdminCallback<TaggedName[]>()
                                          {
                                             @Override
                                             public void onDone(TaggedName[] result)
                                             {
                                                if (result != null && result.length > 0)
                                                {
                                                   getView().getDeletingUsersAlert().setWarningAlert(osUsers);
                                                }
                                                else if (currentIndex + 1 < osUsers.length)
                                                {
                                                   checkAssociatedFwdUsers(osUsers, currentIndex + 1);
                                                }
                                                else
                                                {
                                                   getView().getDeletingUsersAlert().setAlert(osUsers);
                                                }
                                             }
                                          });
   }

   /**
    * Shows the Edit User Account Dialog to edit the target user account.
    * 
    * @param    updatedUserAccount
    *           The target user account given by its tagged name
    */
   @Override
   public void showEditUserAccountDialog(TaggedName updatedUserAccount)
   {
      logger.log(Level.INFO, "showEditUserAccountDialog");
      AddEditOsUserWidget uad = uadProvider.get();
      uad.build(selectedUser, r ->
      {
         if (!r)
         {
            return;
         }

         uad.show(getView().getOsUserDefModalParent(), selectedUser, userDef ->
         {
            if (userDef == null)
            {
               return;
            }

            updateUser(userDef);
            updateUsersList();
         });
      });
   }

   /**
    * Cancels the Add User Account Dialog and rolls back any related changes.
    */
   @Override
   public void cancelAddUserAccountDialog()
   {
      logger.log(Level.INFO, "cancelAddUserAccountDialog");
      restoreState();
   }

   /**
    * Cancels the Deleting Users Alert and rolls back any related changes.
    */
   @Override
   public void cancelDeletingUsersAlert()
   {
      logger.log(Level.INFO, "cancelDeletingUsersAlert");
   }

   /**
    * Cancels the Edit User Account Dialog and rolls back any related changes.
    */
   @Override
   public void cancelEditUserAccountDialog()
   {
      logger.log(Level.INFO, "cancelEditUserAccountDialog");
      restoreState();
   }

   /**
    * Deletes the given selected users accounts.
    * 
    * @param    users
    *           The array of users accounts given by tagged names
    */
   @Override
   public void deleteSelectedUsers(TaggedName[] users)
   {
      if (!getView().isSelectedFromUsers(users))
      {
         return;
      }
      MultiCallback mc = new MultiCallback(adminService, serverAlarmsManager);
      LinkedHashMap<TaggedName, AdminCallback<Boolean>> callbacks = new LinkedHashMap<>();
      for (TaggedName user : users)
      {
         AdminCallback<Boolean> callback = mc.newCallback();
         callbacks.put(user, callback);
         logger.info("OS user account to delete " + user.getName());
      };
      // the admin service must be called only after all callbacks have been created otherwise
      // the onDone method is called unpredictably multiple times
      for (Map.Entry<TaggedName, AdminCallback<Boolean>> e : callbacks.entrySet())
      {
         this.adminService.deleteOsUser(e.getKey().getName(), e.getValue());
      }
      mc.onDone(() ->
      {
         if (!mc.isSuccess())
         {
            // this branch is executed when one or more callbacks !isSuccess()
            for (Map.Entry<TaggedName, AdminCallback<Boolean>> e : callbacks.entrySet())
            {
               if (e.getValue().getResult() == null || !e.getValue().getResult())
               {
                  logger.info("failed to delete OS user account " + e.getKey().getName());
               }
            }
         }
         updateUsersList(()-> changeState(OsUsersViewStates.USERS_LIST_REFRESHED));
      });
   }
   
   /**
    * Triggers the users selection changed event.
    * 
    * @param    users
    *           The selected users accounts
    */
   @Override
   public void onUserSelected(Set<TaggedName> users)
   {
      if (users == null)
      {
         logger.info("Users selection is cleared.");
         changeState(OsUsersViewStates.USERS_LIST_REFRESHED);
         return;
      }
      MultiCallback mc = new MultiCallback(adminService, serverAlarmsManager);
      LinkedHashMap<TaggedName, AdminCallback<OsUserDef>> callbacks = new LinkedHashMap<>();
      users.forEach(user ->
      {
         AdminCallback<OsUserDef> cb = mc.newCallback();
         callbacks.put(user, cb);
         logger.info("get user " + user.getName());
      });
      for (Map.Entry<TaggedName, AdminCallback<OsUserDef>> e : callbacks.entrySet())
      {
         this.adminService.getOsUser(e.getKey().getName(), e.getValue());
      }
      mc.onDone(() ->
      {
         if (mc.isSuccess())
         {
            selectedUsers.clear();
            for (Map.Entry<TaggedName, AdminCallback<OsUserDef>> e : callbacks.entrySet())
            {
               OsUserDef OsUserDef = e.getValue().getResult();
               logger.info("selected user " + OsUserDef);
               selectedUsers.add(OsUserDef);
               selectedUser = OsUserDef;
            }
            if (selectedUsers.size() > 1)
            {
               changeState(OsUsersViewStates.MULTI_USERS_SELECTED);
            }
            else if (selectedUsers.size() == 1)
            {
               changeState(OsUsersViewStates.SINGLE_USER_SELECTED);
               getView().toggleDisableUserButton(selectedUser.enabled);
            }
            else
            {
               changeState(OsUsersViewStates.USERS_LIST_REFRESHED);
            }
         }
         else
         {
            for (Map.Entry<TaggedName, AdminCallback<OsUserDef>> e : callbacks.entrySet())
            {
               if (e.getValue().getResult() == null)
               {
                  logger.info("failed to get user definition for " + e.getKey().getName());
               }
            }
            changeState(OsUsersViewStates.USERS_LIST_REFRESHED);
         }
      });

      if (callbacks.size() == 1)
      {
         TaggedName selectedUser = callbacks.keySet().toArray(new TaggedName [1])[0];
         final String name = selectedUser.getName();
         this.adminService.listAssociatedFwdUsers(name, new AsyncCallback<TaggedName[]>()
         {

            @Override
            public void onSuccess(TaggedName[] result)
            {
               getView().setAssociatedFwdUsers(result);
            }

            @Override
            public void onFailure(Throwable caught)
            {
               logger.log(Level.INFO, "Can't get associated FWD users for the OS user" + name);
            }
         });
      }
      else
      {
         getView().setAssociatedFwdUsers(null);
      }
   }

   /**
    * Adds a new user.
    * 
    * @param    newUser
    *           The new user definition
    */
   @Override
   public void addUser(OsUserDef newUser)
   {
      this.adminService.addOsUser(newUser, new AsyncCallback<Boolean>()
      {
         @Override
         public void onSuccess(Boolean result)
         {
            logger.log(Level.INFO, "addUser " + newUser.subjectId + ", Is added? " + result);
            updateUsersList(()-> restoreState());

            if (result == null || !result)
            {
               serverAlarmsManager.ring("Couldn't add OS user account " + newUser.subjectId);
            }
         }
         
         @Override
         public void onFailure(Throwable caught)
         {
            updateUsersList(()-> restoreState());
         }
      });
   }

   /**
    * Updates a given user account.
    * 
    * @param    user
    *           The given user definition
    */
   @Override
   public void updateUser(OsUserDef user)
   {
      this.adminService.setOsUser(user, new AsyncCallback<Boolean>()
      {
         @Override
         public void onSuccess(Boolean result)
         {
            logger.log(Level.INFO, "updateUser " + user.subjectId + ", Is updated? " + result);
            updateUsersList(()->{getView().selectUserByName(user.subjectId); restoreState();});
         }
         
         @Override
         public void onFailure(Throwable caught)
         {
            updateUsersList(()->{getView().selectUserByName(user.subjectId); restoreState();});
         }
      });
   }
   
   /**
    * Cancels the Find User Account Dialog and rolls back any related changes.
    */
   @Override
   public void cancelFindUserAccountDialog()
   {
   }

   /**
    * Setups the Find User Account Dialog.
    */
   @Override
   public void setupFindUserAccountDialog()
   {
      InputDialog dialog = inputDialogProvider.get();
      IFindAccountScreen findAccount = new IFindAccountScreen()
      {
         @Override
         public void findAccountByName(String name)
         {
            adminService.checkOsUser(
                     name, 
                     new AsyncCallback<TaggedName>()
                     {
                        @Override
                        public void onFailure(Throwable caught)
                        {
                           serverAlarmsManager.ring();
                           modalDialogsManager.showInfo("Can't find OS user " + name + ".");
                        }

                        @Override
                        public void onSuccess(TaggedName result)
                        {
                           if (result != null)
                           {
                              getView().selectUser(result);
                              dialog.dismiss();
                           }
                           else
                           {
                              modalDialogsManager.showInfo("Can't find OS user " + name + ".");
                           }
                        }
                     });
         }
      };
      
      findOsUserAccountManager.show(getView().getOsUserDefModalParent(), dialog, findAccount);
   }

   /**
    * Disables the target user account.
    * 
    * @param    user
    *           The target user account given by its tagged name
    */
   @Override
   public void disableUserAccount(TaggedName user)
   {
      if (selectedUser == null ||
         selectedUser.subjectId == null ||
         !selectedUser.subjectId.equals(user.getName()))
      {
         return;
      }
      boolean enable = !selectedUser.enabled;
      String title   = enable ? "Enable User" : "Disable User";
      String message = (enable ? "Enable user " : "Disable user ") + user.getName() + "?";
      modalDialogsManager.showYesNo(title, message, MessageType.QUESTION, button -> {
         if (button != 0)
         {
            return;
         }
         selectedUser.enabled = enable;
         adminService.setOsUser(selectedUser, new AsyncCallback<Boolean>()
         {
            
            @Override
            public void onFailure(Throwable caught)
            {
               updateUsersList(() -> getView().selectUser(user));
               logger.log(Level.WARNING, "setUser " + user.getName() + " got:", caught);
               modalDialogsManager.showError("Can't " + (enable ? "enable" : "disable") +
                        user.getName() + " user account.");
            }
            
            @Override
            public void onSuccess(Boolean result)
            {
               updateUsersList(() -> getView().selectUser(user));
               if (!result)
               {
                  modalDialogsManager.showError("Can't update to " +
                           (enable ? "enable" : "disable") + user.getName() + " user account.");
               }
            }
         });
      });
   }
}