ProcessesPresenter.java

/*
** Module   : ProcessesPresenter.java
** Abstract : ProcessesPresenter implements business methods to manage process accounts.
**
** Copyright (c) 2017, Golden Code Development Corporation.
**
** -#- -I- --Date-- ----------------Description----------------------
** 001 SBI 20170601 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.processes;


import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.Set;

import javax.inject.Named;

import com.goldencode.p2j.admin.*;
import com.goldencode.p2j.admin.client.AdminCallback;
import com.goldencode.p2j.admin.client.MultiCallback;
import com.goldencode.p2j.admin.client.NameTokens;
import com.goldencode.p2j.admin.client.application.Alarm;
import com.goldencode.p2j.admin.client.application.PrintingContext;
import com.goldencode.p2j.admin.client.application.home.HomePresenter;
import com.goldencode.p2j.admin.client.application.home.ViewStateMachine;
import com.goldencode.p2j.admin.client.application.home.accounts.AccountsPresenter;
import com.goldencode.p2j.admin.client.application.home.acl.*;
import com.goldencode.p2j.admin.client.widget.dialog.MessageType;
import com.goldencode.p2j.admin.client.widget.dialog.ModalDialogs;
import com.goldencode.p2j.admin.shared.AdminServiceAsync;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.web.bindery.event.shared.EventBus;
import com.gwtplatform.mvp.client.HasUiHandlers;
import com.gwtplatform.mvp.client.View;
import com.gwtplatform.mvp.client.annotations.NameToken;
import com.gwtplatform.mvp.client.annotations.ProxyStandard;
import com.gwtplatform.mvp.client.presenter.slots.NestedSlot;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.client.proxy.ProxyPlace;
import com.gwtplatform.mvp.shared.proxy.PlaceRequest;


/**
 * ProcessesPresenter implements business methods to manage process accounts.
 */
public class ProcessesPresenter
extends AccountsPresenter<ProcessesPresenter.MyView, ProcessesPresenter.MyProxy>
implements ProcessesUIHandlers
{

   /** Defines the initial empty state */
   private static final boolean[] STATE_INITIAL_EMPTY =
   {
      /* refreshProcesses     */ true,
      /* addProcess           */ true,
      /* deleteProcessAccounts*/ false,
      /* cloneProcess         */ false,
      /* editProcess          */ false,
      /* disableProcess       */ false,
      /* switchToACLs         */ false,
      /* refreshCerts         */ true,
      /* assignCert           */ false,
      /* switchToCerts        */ false
   };
   
   /** Defines the add new process account state */
   private static final boolean[] STATE_ADD_PROCESS =
   {
      /* refreshProcesses     */ true,
      /* addProcess           */ true,
      /* deleteProcessAccounts*/ false,
      /* cloneProcess         */ false,
      /* editProcess          */ false,
      /* disableProcess       */ false,
      /* switchToACLs         */ false,
      /* refreshCerts         */ true,
      /* assignCert           */ false,
      /* switchToCerts        */ false
   };
   
   /** Defines the edit existing process account state */
   private static final boolean[] STATE_EDIT_PROCESS =
   {
      /* refreshProcesses     */ true,
      /* addProcess           */ true,
      /* deleteProcessAccounts*/ false,
      /* cloneProcess         */ false,
      /* editProcess          */ false,
      /* disableProcess       */ false,
      /* switchToACLs         */ false,
      /* refreshCerts         */ true,
      /* assignCert           */ false,
      /* switchToCerts        */ false
   };
   
   /** Defines the cloning process account state */
   private static final boolean[] STATE_CLONE_PROCESS =
   {
      /* refreshProcesses     */ true,
      /* addProcess           */ true,
      /* deleteProcessAccounts*/ false,
      /* cloneProcess         */ false,
      /* editProcess          */ false,
      /* disableProcess       */ false,
      /* switchToACLs         */ false,
      /* refreshCerts         */ true,
      /* assignCert           */ false,
      /* switchToCerts        */ false
   };
   
   /** state definition - single selection in process accounts list */
   private static final boolean[] STATE_PROCS_SINGLE =
   {
      /* refreshProcesses     */ true,
      /* addProcess           */ true,
      /* deleteProcessAccounts*/ true,
      /* cloneProcess         */ true,
      /* editProcess          */ true,
      /* disableProcess       */ true,
      /* switchToACLs         */ true,
      /* refreshCerts         */ true,
      /* assignCert           */ false,
      /* switchToCerts        */ false
   };
   
   /** state definition - single selection in certificate list */
   private static final boolean[] STATE_CERTS_SINGLE =
   {
      /* refreshProcesses     */ true,
      /* addProcess           */ true,
      /* deleteProcessAccounts*/ false,
      /* cloneProcess         */ false,
      /* editProcess          */ false,
      /* disableProcess       */ false,
      /* switchToACLs         */ false,
      /* refreshCerts         */ true,
      /* assignCert           */ true,
      /* switchToCerts        */ true
   };
   
   /** Defines the state in which the assign certificate action is disabled. */ 
   private static final boolean[] STATE_CERTS_ASSIGN_DISABLED =
   {
      /* refreshProcesses     */ true,
      /* addProcess           */ true,
      /* deleteProcessAccounts*/ false,
      /* cloneProcess         */ false,
      /* editProcess          */ false,
      /* disableProcess       */ false,
      /* switchToACLs         */ false,
      /* refreshCerts         */ true,
      /* assignCert           */ false,
      /* switchToCerts        */ true
   };
   
   /** state definition - multiple selection in process accounts list */
   private static final boolean[] STATE_PROCS_MULTI =
   {
      /* refreshProcesses     */ true,
      /* addProcess           */ true,
      /* deleteProcessAccounts*/ true,
      /* cloneProcess         */ false,
      /* editProcess          */ false,
      /* disableProcess       */ false,
      /* switchToACLs         */ false,
      /* refreshCerts         */ true,
      /* assignCert           */ false,
      /* switchToCerts        */ false
   };
   
   /** mask definition - west */
   private static final boolean[] MASK_WEST =
   {
      /* refreshProcesses     */ true,
      /* addProcess           */ true,
      /* deleteProcessAccounts*/ true,
      /* cloneProcess         */ true,
      /* editProcess          */ true,
      /* disableProcess       */ true,
      /* switchToACLs         */ true,
      /* refreshCerts         */ false,
      /* assignCert           */ false,
      /* switchToCerts        */ false
   };
   
   /** mask definition - east */
   private static final boolean[] MASK_EAST =
   {
      /* refreshProcesses     */ false,
      /* addProcess           */ false,
      /* deleteProcessAccounts*/ false,
      /* cloneProcess         */ false,
      /* editProcess          */ false,
      /* disableProcess       */ false,
      /* switchToACLs         */ false,
      /* refreshCerts         */ true,
      /* assignCert           */ true,
      /* switchToCerts        */ true
   };
   
   /**
    * Defines the Process Accounts View states
    */
   public static enum ProcessesViewStates
   implements ViewStateMachine.TransitionState
   {
      /** The processes list has been refreshed currently */
      PROCESSES_LIST_REFRESHED(MASK_WEST, STATE_INITIAL_EMPTY),
      
      /** The process account has been added currently */
      ADD_PROCESS_ACCOUNT(MASK_WEST, STATE_ADD_PROCESS),
      
      /** The process account has been edited currently */
      EDIT_PROCESS_ACCOUNT(MASK_WEST, STATE_EDIT_PROCESS),
      
      /** The process account has been cloned currently */
      CLONE_PROCESS_ACCOUNT(MASK_WEST, STATE_CLONE_PROCESS),
      
      /** The single account has been selected currently from the all processes table */
      SINGLE_PROCESS_SELECTED(MASK_WEST, STATE_PROCS_SINGLE),
      
      /** The multiple accounts have been selected currently from the all processes table */
      MULTI_PROCESSES_SELECTED(MASK_WEST, STATE_PROCS_MULTI),
      
      /** The certificate has been selected currently from the peer certificates list */
      CERT_SELECTED(MASK_EAST, STATE_CERTS_SINGLE),
      
      /** The action to assign certificate has been disabled currently */
      CERT_ASSIGN_DISABLED(MASK_EAST, STATE_CERTS_ASSIGN_DISABLED);
      
      /** 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
       */
      private ProcessesViewStates(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;
      }
   }

   /**
    * 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<ProcessesUIHandlers>, Provider<HasEnabled[]>, PrintingContext
   {
      /**
       * Sets the all process accounts table model.
       * 
       * @param    processes
       *           The array of process accounts given by tagged names
       */
      void setProcesses(TaggedName[] processes);
      
      /**
       * Sets the peer certificates table model.
       * 
       * @param    certs
       *           The array of peer certificates given by tagged names
       */
      void setCerts(TaggedName[] certs);
      
      /**
       * Tests if the given process account is selected now. 
       * 
       * @param    account
       *           The given process account
       * 
       * @return   True iff this process account is selected now
       */
      boolean isProcessAccountSelected(TaggedName account);
      
      /**
       * Tests if the given set of process accounts is selected now.
       * 
       * @param    accounts
       *           The given set of process accounts
       * 
       * @return   True iff this given set of process accounts is selected now
       */
      boolean isProcessAccountsSelected(Set<TaggedName> accounts);
      
      /**
       * Selects the target process account by its tagged name.
       * 
       * @param    account
       *           The tagged name
       */
      void selectProcessAccount(TaggedName account);
      
      /**
       * Selects the target process account by its account name.
       * 
       * @param    name
       *           The account name
       */
      void selectProcessAccountByName(String name);
      
      /**
       * Assigns the given peer certificate to the selected process account.
       * 
       * @param    selectedAccount
       *           The selected process account
       * @param    alias
       *           The peer certificate alias name
       */
      void setAssignedCert(TaggedName selectedAccount, String alias);
      
      /**
       * Toggles the label of the Disable/Enable process account button.
       * 
       * @param    selectedAccount
       *           The selected process account
       * @param    enabled
       *           The enabled flag which true value indicates that the target buttons label
       *           becomes "Disable Process", otherwise this label becomes "Enable Process".
       */
      void toggleDisableProcessButton(TaggedName selectedAccount, boolean enabled);
      
      /**
       * Tests if the given peer certificate is selected.
       * 
       * @param    cert
       *           The given peer certificate
       * 
       * @return   True iff the given peer certificate is selected, otherwise false.
       */
      boolean isCertificateSelected(TaggedName cert);

      /**
       * Gets a reference to the Clone Process Account View.
       * 
       * @return   The Clone Group View
       */
      CloneProcessView getCloneProcessView();

      /**
       * Returns the parent container where the Add/Edit Process Account Definition View will be
       * revealed in.
       * 
       * @return   The parent container for the Add/Edit Process Account Definition View.
       */
      HasWidgets getProcDefModalParent();
   }
   
   /**
    * Defines the proxy place for GWTP framework.
    */
   @ProxyStandard
   @NameToken(NameTokens.PROCESSES)
   public interface MyProxy
   extends ProxyPlace<ProcessesPresenter>
   {}
   
   /** 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 current selected set of process accounts */ 
   private final Set<ProcessDef> selectedProcesses = new HashSet<ProcessDef>();
   
   /** The current single selected process account */
   private ProcessDef selectedProcessAccount;
   
   /** The process account definition provider */
   private final Provider<ProcessAccountDefinition> padProvider;
   
   /**
    * Constructs this presenter(controller) used by MPV gwtplatform of ArcBees Inc.
    * 
    * @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    padProvider
    *           The process account definition provider
    * @param    aclPopupPresenterProvider
    *           The ACL popup presenter provider
    */
   @Inject
   public ProcessesPresenter(EventBus eventBus,
                             MyView view,
                             MyProxy proxy,
                             PlaceManager placeManager,
                             @Named("ProcessesViewStateMachine")
                             ViewStateMachine viewStateMachine,
                             AdminServiceAsync adminService,
                             ModalDialogs modalDialogsManager,
                             Alarm serverAlarmsManager,
                             Provider<ProcessAccountDefinition> padProvider,
                             ACLPopupPresenter aclPopupPresenterProvider)
   {
      super(eventBus,
            view,
            proxy,
            HomePresenter.SLOT_CONTENT,
            placeManager,
            viewStateMachine,
            aclPopupPresenterProvider);

      this.adminService = adminService;
      this.modalDialogsManager = modalDialogsManager;
      this.serverAlarmsManager = serverAlarmsManager;
      this.padProvider = padProvider;
      getView().setUiHandlers(this);
   }
   
   /**
    * Loads the data before the associated view will be displayed.
    * 
    * @param    request
    *           The current request
    */
   @Override
   public void prepareFromRequest(PlaceRequest request)
   {
      super.prepareFromRequest(request);
      updateProcesses();
      updateCerts();
      setState(ProcessesViewStates.PROCESSES_LIST_REFRESHED);
   }
   
   /**
    * Handles the action to refresh the table of process accounts.
    */
   @Override
   public void onRefreshProcesses()
   {
      updateProcesses(()->{setState(ProcessesViewStates.PROCESSES_LIST_REFRESHED);});
   }
   
   /**
    * Handles the action to refresh the table of certificates.
    */
   @Override
   public void onRefreshCerts()
   {
      updateCerts();
   }
   
   /**
    * Updates the process accounts data model asynchronously.
    */
   private void updateProcesses()
   {
      updateProcesses(()->{});
   }
   
   /**
    * Updates the process accounts data model asynchronously and executes the given command if
    * this action has been complete successfully or has been failed.
    * 
    * @param    command
    *           The given command
    */
   private void updateProcesses(Runnable command)
   {
      this.adminService.listProcesses(new AsyncCallback<TaggedName[]>()
      {
         
         @Override
         public void onSuccess(TaggedName[] processes)
         {
            getView().setProcesses(processes);
            command.run();
         }
         
         @Override
         public void onFailure(Throwable caught)
         {
            command.run();
            serverAlarmsManager.ring("Failed to get processes");
         }
      });
   }
   
   /**
    * Updates the peer certificates data model asynchronously.
    */
   private void updateCerts()
   {
      updateCerts(()->{});
   }
   
   /**
    * Updates the peer certificates data model asynchronously and executes the given command if
    * this action has been complete successfully or has been failed.
    * 
    * @param    command
    *           The given command
    */
   private void updateCerts(Runnable command)
   {
      this.adminService.listPeerCerts(false, new AsyncCallback<TaggedName[]>()
      {
         
         @Override
         public void onSuccess(TaggedName[] certs)
         {
            getView().setCerts(certs);
            command.run();
         }
         
         @Override
         public void onFailure(Throwable caught)
         {
            command.run();
            serverAlarmsManager.ring("Failed to get peer certificates");
         }
      });
   }
   
   /**
    * Cancels the Add Process Account Dialog.
    */
   @Override
   public void cancelAddProcessAccountDialog()
   {
      restoreState();
   }
   
   /**
    * Cancels the Edit Process Account Dialog.
    */
   @Override
   public void cancelEditProcessAccountDialog()
   {
      restoreState();
   }
   
   /**
    * Shows the Add Process Account Dialog.
    */
   @Override
   public void showAddProcessAccountDialog()
   {
      ProcessAccountDefinition pad = padProvider.get();
      pad.build(null, r ->
      {
         if (!r)
         {
            return;
         }

         pad.show(getView().getProcDefModalParent(), new ProcessDef(), pdata ->
         {
            if (pdata == null)
            {
               return;
            }

            addProcess(pdata.processDef, pdata.extDef);
            updateProcesses();
         });
      });
   }

   /**
    * Shows the Edit Process Account Dialog.
    * 
    * @param    selected
    *           The process account given by its tagged name
    */
   @Override
   public void showEditProcessAccountDialog(TaggedName selected)
   {
      ProcessAccountDefinition pad = padProvider.get();
      pad.build(selectedProcessAccount, r ->
      {
         if (!r)
         {
            return;
         }

         pad.show(getView().getProcDefModalParent(), selectedProcessAccount, pdata ->
         {
            if (pdata == null)
            {
               return;
            }

            updateProcess(pdata.processDef, pdata.extDef);
            updateProcesses();
         });
      });
   }
   
   /**
    * Setups the Clone Process Account Dialog.
    * 
    * @param    selected
    *           The process account given by its tagged name
    */
   @Override
   public void setupCloneProcessAccountDialog(TaggedName selected)
   {
      getView().getCloneProcessView().setupClonedProcess(selected);
   }
   
   /**
    * Handles the process accounts selection changed action.
    * 
    * @param    selected
    *           The set of selected process accounts given by tagged names
    */
   @Override
   public void onProcessSelectionChanged(Set<TaggedName> selected)
   {
      if (selected == null || selected.isEmpty())
      {
         return;
      }
      
      MultiCallback mc = new MultiCallback(adminService, serverAlarmsManager);
      LinkedHashMap<TaggedName, AdminCallback<ProcessDef>> callbacks = new LinkedHashMap<TaggedName, AdminCallback<ProcessDef>>();
      selected.forEach(ps -> {
         callbacks.put(ps, mc.newCallback());
         logger.info("get process definition for " + ps.getName());
      });
      for(Entry<TaggedName, AdminCallback<ProcessDef>> e : callbacks.entrySet())
      {
         adminService.getProcess(e.getKey().getName(), e.getValue());
      }
      
      mc.onDone(() -> {
         selectedProcesses.clear();
         selectedProcessAccount = null;
         if (mc.isSuccess())
         {
            for(Entry<TaggedName, AdminCallback<ProcessDef>> e : callbacks.entrySet())
            {
               ProcessDef ps = e.getValue().getResult();
               selectedProcesses.add(ps);
            }
            if (selectedProcesses.size() > 1)
            {
               updateCerts(() -> {
                  setState(ProcessesViewStates.MULTI_PROCESSES_SELECTED);
               });
            }
            else if (selectedProcesses.size() == 1)
            {
               selectedProcessAccount = selectedProcesses.toArray(new ProcessDef[1])[0];
               String alias = selectedProcessAccount.alias;
               boolean enabledAccount = selectedProcessAccount.enabled;
               TaggedName selectedAccount = callbacks.keySet().toArray(new TaggedName [1])[0];
               setState(ProcessesViewStates.SINGLE_PROCESS_SELECTED);
               getView().toggleDisableProcessButton(selectedAccount, enabledAccount);
               getView().setAssignedCert(selectedAccount, alias);
            }
            else
            {
               updateCerts(() -> {
                  setState(ProcessesViewStates.PROCESSES_LIST_REFRESHED);
               });
            }
         }
         else
         {
            for(Entry<TaggedName, AdminCallback<ProcessDef>> e : callbacks.entrySet())
            {
               if (e.getValue().getResult() == null)
               {
                  logger.info("failed to get process definition for " + e.getKey().getName());
               }
            }
            updateCerts(() -> {
               setState(ProcessesViewStates.PROCESSES_LIST_REFRESHED);
            });
         }
      });
      
   }

   /**
    * Cancels the Clone Process Account Dialog.
    */
   @Override
   public void cancelCloneProcessAccountDialog()
   {
   }

   /**
    * Adds the new process account.
    * 
    * @param    accountDef
    *           The process account definition
    * @param    ext
    *           The account extension object
    */
   @Override
   public void addProcess(ProcessDef accountDef, Serializable ext)
   {
      adminService.addProcess(accountDef, ext, new AsyncCallback<Boolean>()
      {
         @Override
         public void onFailure(Throwable caught)
         {
            logger.log(Level.SEVERE, "Couldn't add process account " + accountDef.subjectId, caught);
            updateProcesses();
            restoreState();
         }

         @Override
         public void onSuccess(Boolean result)
         {
            updateProcesses();
            if (result == null || !result)
            {
               serverAlarmsManager.ring("Couldn't add process account " + accountDef.subjectId);
            }
            restoreState();
         }
      });
   }

   /**
    * Updates the given process account.
    * 
    * @param    accountDef
    *           The given process account definition
    * @param    ext
    *           The given account extension object
    */
   @Override
   public void updateProcess(ProcessDef accountDef, Serializable ext)
   {
      adminService.setProcess(accountDef, ext, new AsyncCallback<Boolean>()
      {
         @Override
         public void onFailure(Throwable caught)
         {
            logger.log(Level.SEVERE, "Couldn't update process account " + accountDef.subjectId, caught);
            updateProcesses(()->{getView().selectProcessAccountByName(accountDef.subjectId);});
            restoreState();
         }

         @Override
         public void onSuccess(Boolean result)
         {
            updateProcesses(()->{getView().selectProcessAccountByName(accountDef.subjectId);});
            if (result == null || !result)
            {
               serverAlarmsManager.ring("Couldn't update process account " + accountDef.subjectId);
            }
            restoreState();
         }
      });
   }

   /**
    * Executes the action to disable the given process account.
    * 
    * @param    ps
    *           The process account given by its tagged name
    */
   @Override
   public void disableProcessAccount(TaggedName ps)
   {
      if (selectedProcessAccount == null || selectedProcessAccount.subjectId == null ||
               !selectedProcessAccount.subjectId.equals(ps.getName()))
      {
         return;
      }
      boolean enable = !selectedProcessAccount.enabled;
      String title   = enable ? "Enable Process" : "Disable Process";
      String message = (enable ? "Enable Process '" : "Disable Process '") + ps.getName() + "'?";
      modalDialogsManager.showYesNo(title, message, MessageType.QUESTION, button -> {
         
         if (button == 0)
         {
            selectedProcessAccount.enabled = enable;
            adminService.setProcess(selectedProcessAccount, new AsyncCallback<Boolean>()
            {
               
               @Override
               public void onFailure(Throwable caught)
               {
                  updateProcesses(() -> {getView().selectProcessAccount(ps);});
                  logger.log(Level.SEVERE, "setProcess " + ps.getName() + " got " + caught);
                  modalDialogsManager.showError("Can't " + (enable ? "enable" : "disable") +
                           ps.getName() + " process account.");
               }
               
               @Override
               public void onSuccess(Boolean result)
               {
                  updateProcesses(() -> {getView().selectProcessAccount(ps);});
                  if (!result)
                  {
                     serverAlarmsManager.ring("Can't update to " +
                              (enable ? "enable" : "disable") + ps.getName() + " process account.");
                  }
               }
            });
         }
      });
   }
   
   /**
    * Clones the process account with its ACL if it is chosen.
    * 
    * @param    nameFrom
    *           The cloning process account name
    * @param    nameTo
    *           The new cloned process account name
    * @param    acls
    *           The flag that requests to clone the process account ACL
    */
   @Override
   public void cloneProcess(String nameFrom, String nameTo, boolean acls)
   {
      adminService.cloneProcess(nameFrom, nameTo, acls, new AsyncCallback<Boolean>()
      {

         @Override
         public void onFailure(Throwable caught)
         {
            logger.log(Level.SEVERE, "cloneProcess('" + nameFrom + "', '" + nameTo + "', '" + acls + "') got " + caught);
            onRefreshProcesses();
         }

         @Override
         public void onSuccess(Boolean result)
         {
            if (!result)
            {
               serverAlarmsManager.ring("Can't clone process " + nameFrom);
            }
            onRefreshProcesses();
         }
      });
   }

   /**
    * Executes the action to delete the given process accounts
    * 
    * @param    accounts
    *           The process accounts to be deleted
    */
   @Override
   public void deleteProcessAccounts(Set<TaggedName> accounts)
   {
      if (accounts == null || accounts.isEmpty())
      {
         return;
      }
      int size = accounts.size();
      String message;
      if (size > 1)
      {
         message = size + " process accounts being deleted. Continue?";
      }
      else
      {
         message = "1 process account being deleted. Continue?";
      }
      String title   = "Deleting Process Accounts";
      modalDialogsManager.showYesNo(title, message, MessageType.QUESTION, button -> {
         
         if (button == 0)
         {
            MultiCallback mc = new MultiCallback(adminService, serverAlarmsManager);
            LinkedHashMap<TaggedName, AdminCallback<Boolean>> callbacks = new LinkedHashMap<TaggedName, AdminCallback<Boolean>>();
            for(TaggedName ps : accounts)
            {
               AdminCallback<Boolean> callback = mc.newCallback();
               callbacks.put(ps, callback);
               logger.info("process account to delete " + ps.getName());
            };
            for (Map.Entry<TaggedName, AdminCallback<Boolean>> e : callbacks.entrySet())
            {
               this.adminService.deleteProcess(e.getKey().getName(), e.getValue());
            }
            mc.onDone(() ->
            {
               onRefreshProcesses();
               if (!mc.isSuccess())
               {
                  for (Map.Entry<TaggedName, AdminCallback<Boolean>> e : callbacks.entrySet())
                  {
                     if (e.getValue().getResult() == null || !e.getValue().getResult())
                     {
                        logger.info("failed to delete process account " + e.getKey().getName());
                     }
                  }
               }
            });
         }
      });
   }

   /**
    * Handles the certificate selection changed action.
    * 
    * @param    selectedCert
    *           The selected certificate
    */
   @Override
   public void onCertificateSelectionChanged(TaggedName selectedCert)
   {
      if (!getView().isCertificateSelected(selectedCert))
      {
         return;
      }
      
      if (selectedProcessAccount != null)
      {
         String alias = selectedCert.getName();
         boolean alreadyAssigned = (selectedProcessAccount.alias != null &&
                  selectedProcessAccount.alias.equals(alias));
         if (!alreadyAssigned)
         {
            changeState(ProcessesViewStates.CERT_SELECTED);
         }
         else
         {
            changeState(ProcessesViewStates.CERT_ASSIGN_DISABLED);
         }
      }
      else
      {
         changeState(ProcessesViewStates.CERT_ASSIGN_DISABLED);
      }
   }

   /**
    * Executes the action to assign the selected certificate to the selected process account.
    * 
    * @param    selectedCert
    *           The selected certificate given by its tagged name
    * @param    selectedProcess
    *           The selected process account given by its tagged name
    */
   @Override
   public void assignCertificateToProcess(TaggedName selectedCert, TaggedName selectedProcess)
   {
      if (!getView().isCertificateSelected(selectedCert) ||
               !getView().isProcessAccountSelected(selectedProcess))
      {
         return;
      }
      String title   = "Assign Certificate";
      String message = "Assign certificate " + "'" + selectedCert.getName() + "'" + " to process " +
               "'" + selectedProcess.getName() + "'" + "?"; 
      modalDialogsManager.showYesNo(title, message, MessageType.QUESTION, (button) -> {
         if (button == 0)
         {
            adminService.getProcess(selectedProcess.getName(), new AsyncCallback<ProcessDef>()
            {

               @Override
               public void onFailure(Throwable caught)
               {
                  logger.log(Level.SEVERE, "Failed to call getProcess", caught);
               }

               @Override
               public void onSuccess(ProcessDef result)
               {
                  result.alias = selectedCert.getName();
                  updateProcess(result, null);
               }
            });
         }
      });
   }

   /**
    * Executes the action to switch to the Certificate Management view.
    * 
    * @param    selected
    *           The certificate given by its tagged name
    */
   @Override
   public void switchToCertificates(TaggedName selected)
   {
      PlaceRequest request = new PlaceRequest.Builder().nameToken(NameTokens.CERTS).with("alias",
               selected.getName()).with("CertificatesOptions", "PEER").build();
      getPlaceManager().revealPlace(request);
   }
}