net.webpasswordsafe.client.WebPasswordSafe.java Source code

Java tutorial

Introduction

Here is the source code for net.webpasswordsafe.client.WebPasswordSafe.java

Source

/*
Copyright 2008-2015 Josh Drummond
    
This file is part of WebPasswordSafe.
    
WebPasswordSafe is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
    
WebPasswordSafe 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 General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with WebPasswordSafe; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
package net.webpasswordsafe.client;

import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import net.webpasswordsafe.client.i18n.TextMessages;
import net.webpasswordsafe.client.remote.LoginService;
import net.webpasswordsafe.client.remote.PasswordService;
import net.webpasswordsafe.client.remote.ServiceHelper;
import net.webpasswordsafe.client.remote.UserService;
import net.webpasswordsafe.client.ui.*;
import net.webpasswordsafe.common.dto.SystemSettings;
import net.webpasswordsafe.common.model.AccessLevel;
import net.webpasswordsafe.common.model.Group;
import net.webpasswordsafe.common.model.Password;
import net.webpasswordsafe.common.model.Permission;
import net.webpasswordsafe.common.model.Template;
import net.webpasswordsafe.common.model.User;
import net.webpasswordsafe.common.util.Constants;
import net.webpasswordsafe.common.util.Constants.Function;
import com.extjs.gxt.ui.client.Style.Orientation;
import com.extjs.gxt.ui.client.event.MenuEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.util.Format;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.util.Padding;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.Viewport;
import com.extjs.gxt.ui.client.widget.layout.FillLayout;
import com.extjs.gxt.ui.client.widget.layout.HBoxLayout;
import com.extjs.gxt.ui.client.widget.layout.HBoxLayoutData;
import com.extjs.gxt.ui.client.widget.layout.RowData;
import com.extjs.gxt.ui.client.widget.layout.RowLayout;
import com.extjs.gxt.ui.client.widget.layout.HBoxLayout.HBoxLayoutAlign;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.menu.MenuBar;
import com.extjs.gxt.ui.client.widget.menu.MenuBarItem;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.rpc.XsrfToken;
import com.google.gwt.user.client.rpc.XsrfTokenService;
import com.google.gwt.user.client.rpc.XsrfTokenServiceAsync;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 * 
 * @author Josh Drummond
 * 
 */
public class WebPasswordSafe implements EntryPoint, MainWindow, LoginWindow {
    private Logger log = Logger.getLogger(WebPasswordSafe.class.getName());
    private ClientSessionUtil clientSessionUtil = ClientSessionUtil.getInstance();
    private final static TextMessages textMessages = GWT.create(TextMessages.class);
    private Viewport viewport;
    private ContentPanel mainPanel, topPanel, menuPanel;
    private PasswordSearchPanel passwordSearchPanel;

    public void onModuleLoad() {
        // menu panel
        menuPanel = new ContentPanel(new FillLayout());
        menuPanel.setHeaderVisible(false);
        menuPanel.setBorders(false);

        refreshMenu();

        viewport = new Viewport();
        viewport.setLayout(new RowLayout(Orientation.VERTICAL));
        // title panel
        topPanel = new ContentPanel();
        HBoxLayout titleLayout = new HBoxLayout();
        titleLayout.setPadding(new Padding(5));
        titleLayout.setHBoxLayoutAlign(HBoxLayoutAlign.TOP);
        topPanel.setLayout(titleLayout);
        topPanel.setHeight(25);
        topPanel.setHeaderVisible(false);
        topPanel.setBorders(false);
        refreshTopPanel();
        viewport.add(topPanel, new RowData(1, -1));
        //menu panel
        viewport.add(menuPanel, new RowData(1, -1));
        //main panel
        mainPanel = new ContentPanel(new FillLayout());
        mainPanel.setHeaderVisible(false);
        viewport.add(mainPanel, new RowData(1, 1));

        RootPanel.get().add(viewport);

        log.info(textMessages.webpasswordsafeTitle(Constants.VERSION));
        pingServer(this);
    }

    private void refreshTopPanel() {
        topPanel.removeAll();
        Text headerGwtLabel = new Text(textMessages.webpasswordsafeTitle(Constants.VERSION));
        Text loggedInLabel = null;
        if (clientSessionUtil.isLoggedIn()) {
            loggedInLabel = new Text(
                    textMessages.loggedInAs(Format.htmlEncode(clientSessionUtil.getLoggedInUser().getFullname())));
        } else {
            loggedInLabel = new Text(textMessages.notLoggedIn());
        }
        topPanel.add(headerGwtLabel, new HBoxLayoutData(0, 5, 0, 0));
        HBoxLayoutData flex = new HBoxLayoutData(new Margins(0, 5, 0, 0));
        flex.setFlex(1);
        topPanel.add(new Text(), flex);
        topPanel.add(loggedInLabel, new HBoxLayoutData(new Margins(0)));
        topPanel.layout();
    }

    private void doChangePassword() {
        new ChangePasswordDialog().show();
    }

    private void doTwoStepVerificationSettings() {
        new TwoStepVerificationDialog().show();
    }

    private void refreshPasswordSearch() {
        mainPanel.removeAll();
        if (clientSessionUtil.isLoggedIn()) {
            passwordSearchPanel = new PasswordSearchPanel();
            passwordSearchPanel.setSize("100%", "100%");
            mainPanel.add(passwordSearchPanel);
        }
        mainPanel.layout();
    }

    private void refreshMenu() {
        MenuBar mainMenu = new MenuBar();

        buildUserMenu(mainMenu);
        buildPasswordMenu(mainMenu);
        buildAdminMenu(mainMenu);
        buildReportsMenu(mainMenu);
        buildAboutMenu(mainMenu);

        menuPanel.removeAll();
        menuPanel.add(mainMenu);
        menuPanel.layout();
    }

    private void buildUserMenu(MenuBar mainMenu) {
        Menu userMenu = new Menu();
        MenuItem userSettings = new MenuItem(textMessages.settings());
        Menu userSettingsMenu = new Menu();
        //userSettingsMenu.add(new MenuItem("General"));
        userSettingsMenu.add(new MenuItem(textMessages.changePassword(), new SelectionListener<MenuEvent>() {
            @Override
            public void componentSelected(MenuEvent ce) {
                doChangePassword();
            }
        }));
        userSettingsMenu.add(new MenuItem(textMessages.twoStepVerification(), new SelectionListener<MenuEvent>() {
            @Override
            public void componentSelected(MenuEvent ce) {
                doTwoStepVerificationSettings();
            }
        }));
        userSettings.setSubMenu(userSettingsMenu);
        userMenu.add(userSettings);

        //        MenuItem userRole = new MenuItem("Role");
        //        Menu userRoleMenu = new Menu();
        //        userRoleMenu.add(new MenuItem("User"));
        //        userRoleMenu.add(new MenuItem("Admin"));
        //        userRole.setSubMenu(userRoleMenu);
        //        userMenu.add(userRole);

        userMenu.add(new MenuItem(textMessages.logout(), new SelectionListener<MenuEvent>() {
            @Override
            public void componentSelected(MenuEvent ce) {
                doLogout();
            }
        }));

        mainMenu.add(new MenuBarItem(textMessages.user(), userMenu));
    }

    private void buildPasswordMenu(MenuBar mainMenu) {
        Menu passwordMenu = new Menu();
        if (clientSessionUtil.isAuthorized(Function.ADD_PASSWORD)) {
            passwordMenu.add(new MenuItem(textMessages.add(), new SelectionListener<MenuEvent>() {
                @Override
                public void componentSelected(MenuEvent ce) {
                    doNewPassword();
                }
            }));
        }
        MenuItem passwordSearch = new MenuItem(textMessages.search());
        Menu passwordSearchMenu = new Menu();
        passwordSearchMenu
                .add(new MenuItem(textMessages.openSelectedPassword(), new SelectionListener<MenuEvent>() {
                    @Override
                    public void componentSelected(MenuEvent ce) {
                        if (null != passwordSearchPanel) {
                            passwordSearchPanel.openSelectedPassword();
                        }
                    }
                }));
        passwordSearchMenu
                .add(new MenuItem(textMessages.getSelectedPasswordValue(), new SelectionListener<MenuEvent>() {
                    @Override
                    public void componentSelected(MenuEvent ce) {
                        if (null != passwordSearchPanel) {
                            passwordSearchPanel.getSelectedCurrentPasswordData();
                        }
                    }
                }));
        passwordSearchMenu.add(new MenuItem(textMessages.refreshSearch(), new SelectionListener<MenuEvent>() {
            @Override
            public void componentSelected(MenuEvent ce) {
                refreshPasswordSearch();
            }
        }));
        passwordSearch.setSubMenu(passwordSearchMenu);
        passwordMenu.add(passwordSearch);

        MenuItem passwordTemplate = new MenuItem(textMessages.template());
        Menu passwordTemplateMenu = new Menu();
        if (clientSessionUtil.isAuthorized(Function.ADD_TEMPLATE)) {
            passwordTemplateMenu.add(new MenuItem(textMessages.add(), new SelectionListener<MenuEvent>() {
                @Override
                public void componentSelected(MenuEvent ce) {
                    doAddTemplate();
                }
            }));
        }
        if (clientSessionUtil.isAuthorized(Function.UPDATE_TEMPLATE)) {
            passwordTemplateMenu.add(new MenuItem(textMessages.edit(), new SelectionListener<MenuEvent>() {
                @Override
                public void componentSelected(MenuEvent ce) {
                    doEditTemplate();
                }
            }));
        }
        passwordTemplate.setSubMenu(passwordTemplateMenu);
        passwordMenu.add(passwordTemplate);

        mainMenu.add(new MenuBarItem(textMessages.password(), passwordMenu));
    }

    private void buildAdminMenu(MenuBar mainMenu) {
        // only create admin menu item if submenus allowed
        if (clientSessionUtil.isAuthorized(Function.ADD_USER)
                || clientSessionUtil.isAuthorized(Function.UPDATE_USER)
                || clientSessionUtil.isAuthorized(Function.ADD_GROUP)
                || clientSessionUtil.isAuthorized(Function.UPDATE_GROUP)
                || clientSessionUtil.isAuthorized(Function.UNBLOCK_IP)) {
            Menu adminMenu = new Menu();
            //adminMenu.add(new MenuItem("Settings"));

            MenuItem adminUser = new MenuItem(textMessages.users());
            Menu adminUserMenu = new Menu();
            if (clientSessionUtil.isAuthorized(Function.ADD_USER)) {
                adminUserMenu.add(new MenuItem(textMessages.add(), new SelectionListener<MenuEvent>() {
                    @Override
                    public void componentSelected(MenuEvent ce) {
                        doAddUser();
                    }
                }));
            }
            if (clientSessionUtil.isAuthorized(Function.UPDATE_USER)) {
                adminUserMenu.add(new MenuItem(textMessages.edit(), new SelectionListener<MenuEvent>() {
                    @Override
                    public void componentSelected(MenuEvent ce) {
                        doEditUser();
                    }
                }));
            }
            adminUser.setSubMenu(adminUserMenu);
            adminMenu.add(adminUser);

            MenuItem adminGroup = new MenuItem(textMessages.groups());
            Menu adminGroupMenu = new Menu();
            if (clientSessionUtil.isAuthorized(Function.ADD_GROUP)) {
                adminGroupMenu.add(new MenuItem(textMessages.add(), new SelectionListener<MenuEvent>() {
                    @Override
                    public void componentSelected(MenuEvent ce) {
                        doAddGroup();
                    }
                }));
            }
            if (clientSessionUtil.isAuthorized(Function.UPDATE_GROUP)) {
                adminGroupMenu.add(new MenuItem(textMessages.edit(), new SelectionListener<MenuEvent>() {
                    @Override
                    public void componentSelected(MenuEvent ce) {
                        doEditGroup();
                    }
                }));
            }
            adminGroup.setSubMenu(adminGroupMenu);
            adminMenu.add(adminGroup);

            MenuItem adminTools = new MenuItem(textMessages.tools());
            Menu adminToolsMenu = new Menu();
            if (clientSessionUtil.isAuthorized(Function.UNBLOCK_IP)) {
                adminToolsMenu.add(new MenuItem(textMessages.unblockIP(), new SelectionListener<MenuEvent>() {
                    @Override
                    public void componentSelected(MenuEvent ce) {
                        doUnblockIP();
                    }
                }));
            }
            adminTools.setSubMenu(adminToolsMenu);
            adminMenu.add(adminTools);

            mainMenu.add(new MenuBarItem(textMessages.admin(), adminMenu));
        }
        //        MenuItem adminRole = new MenuItem("Roles");
        //        adminMenu.add(adminRole);
    }

    private void buildReportsMenu(MenuBar mainMenu) {
        Menu reportsMenu = new Menu();
        List<Map<String, Object>> reports = getClientModel().getAvailableReports();
        for (final Map<String, Object> report : reports) {
            MenuItem menuItem = new MenuItem((String) report.get(Constants.I18N),
                    new SelectionListener<MenuEvent>() {
                        @Override
                        public void componentSelected(MenuEvent ce) {
                            displayReportDialog(report);
                        }
                    });
            reportsMenu.add(menuItem);
        }
        mainMenu.add(new MenuBarItem(textMessages.reports(), reportsMenu));
    }

    private void displayReportDialog(Map<String, Object> report) {
        new ReportDialog(report).show();
    }

    private void buildAboutMenu(MenuBar mainMenu) {
        Menu aboutMenu = new Menu();
        aboutMenu.add(new MenuItem(textMessages.help(), new SelectionListener<MenuEvent>() {
            @Override
            public void componentSelected(MenuEvent ce) {
                doShowHelp();
            }
        }));
        aboutMenu.add(new MenuItem(textMessages.about(), new SelectionListener<MenuEvent>() {
            @Override
            public void componentSelected(MenuEvent ce) {
                doShowAbout();
            }
        }));

        mainMenu.add(new MenuBarItem(textMessages.about(), aboutMenu));
    }

    private void doNewPassword() {
        if (clientSessionUtil.isAuthorized(Function.ADD_PASSWORD)) {
            Password newPassword = new Password();
            newPassword.setMaxEffectiveAccessLevel(AccessLevel.GRANT);
            newPassword.addPermission(new Permission(clientSessionUtil.getLoggedInUser(), AccessLevel.GRANT));
            new PasswordDialog(newPassword, passwordSearchPanel).show();
        } else {
            MessageBox.alert(textMessages.error(), textMessages.notAuthorized(), null);
        }
    }

    private void doEditGroup() {
        if (clientSessionUtil.isAuthorized(Function.UPDATE_GROUP)) {
            AsyncCallback<List<Group>> callback = new AsyncCallback<List<Group>>() {
                @Override
                public void onFailure(Throwable caught) {
                    WebPasswordSafe.handleServerFailure(caught);
                }

                @Override
                public void onSuccess(List<Group> result) {
                    new GroupSelectionDialog(new EditGroupListener(), result, false).show();
                }
            };
            UserService.Util.getInstance().getGroups(false, callback);
        } else {
            MessageBox.alert(textMessages.error(), textMessages.notAuthorized(), null);
        }
    }

    private void doAddGroup() {
        if (clientSessionUtil.isAuthorized(Function.ADD_GROUP)) {
            displayGroupDialog(new Group());
        } else {
            MessageBox.alert(textMessages.error(), textMessages.notAuthorized(), null);
        }
    }

    private void doUnblockIP() {
        if (clientSessionUtil.isAuthorized(Function.UNBLOCK_IP)) {
            displayIPUnblockDialog();
        } else {
            MessageBox.alert(textMessages.error(), textMessages.notAuthorized(), null);
        }
    }

    private void displayIPUnblockDialog() {
        new IPUnblockDialog().show();
    }

    private void displayGroupDialog(Group group) {
        new GroupDialog(group).show();
    }

    @Override
    public void refreshLoginStatus() {
        refreshTopPanel();
        refreshMenu();
        refreshPasswordSearch();
    }

    private void doAddUser() {
        if (clientSessionUtil.isAuthorized(Function.ADD_USER)) {
            displayUserDialog(new User());
        } else {
            MessageBox.alert(textMessages.error(), textMessages.notAuthorized(), null);
        }
    }

    private void doEditUser() {
        if (clientSessionUtil.isAuthorized(Function.UPDATE_USER)) {
            AsyncCallback<List<User>> callback = new AsyncCallback<List<User>>() {
                @Override
                public void onFailure(Throwable caught) {
                    WebPasswordSafe.handleServerFailure(caught);
                }

                @Override
                public void onSuccess(List<User> result) {
                    new UserSelectionDialog(new EditUserListener(), result, false).show();
                }
            };
            UserService.Util.getInstance().getUsers(false, callback);
        } else {
            MessageBox.alert(textMessages.error(), textMessages.notAuthorized(), null);
        }
    }

    private void doAddTemplate() {
        if (clientSessionUtil.isAuthorized(Function.ADD_TEMPLATE)) {
            displayTemplateDialog(new Template());
        } else {
            MessageBox.alert(textMessages.error(), textMessages.notAuthorized(), null);
        }
    }

    private void doEditTemplate() {
        if (clientSessionUtil.isAuthorized(Function.UPDATE_TEMPLATE)) {
            AsyncCallback<List<Template>> callback = new AsyncCallback<List<Template>>() {
                @Override
                public void onFailure(Throwable caught) {
                    WebPasswordSafe.handleServerFailure(caught);
                }

                @Override
                public void onSuccess(List<Template> result) {
                    new TemplateSelectionDialog(new EditTemplateListener(), result, false).show();
                }
            };
            PasswordService.Util.getInstance().getTemplates(true, callback);
        } else {
            MessageBox.alert(textMessages.error(), textMessages.notAuthorized(), null);
        }
    }

    private void displayTemplateDialog(Template template) {
        new TemplateDialog(template).show();
    }

    private void pingServer(final LoginWindow loginWindow) {
        AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>() {
            @Override
            public void onFailure(Throwable caught) {
                WebPasswordSafe.handleServerFailure(caught);
            }

            @Override
            public void onSuccess(Boolean result) {
                initXsrfProtection(loginWindow);
            }
        };
        LoginService.Util.getInstance().ping(callback);
    }

    private void initXsrfProtection(final LoginWindow loginWindow) {
        XsrfTokenServiceAsync xsrf = (XsrfTokenServiceAsync) GWT.create(XsrfTokenService.class);
        ((ServiceDefTarget) xsrf).setServiceEntryPoint(GWT.getModuleBaseURL() + "xsrf");
        xsrf.getNewXsrfToken(new AsyncCallback<XsrfToken>() {
            @Override
            public void onSuccess(XsrfToken token) {
                ServiceHelper.setXsrfToken(token);
                getSystemSettings(loginWindow);
            }

            @Override
            public void onFailure(Throwable caught) {
                WebPasswordSafe.handleServerFailure(caught);
            }
        });
    }

    @Override
    public void doGetLoggedInUser(final LoginWindow loginWindow) {
        AsyncCallback<User> callback = new AsyncCallback<User>() {
            @Override
            public void onFailure(Throwable caught) {
                WebPasswordSafe.handleServerFailure(caught);
            }

            @Override
            public void onSuccess(User result) {
                if (null != result) {
                    getClientModel().setLoggedInUser(result);
                    getClientModel().setLoggedIn(true);
                    getLoginAuthorizations(loginWindow);
                } else {
                    loginWindow.doGetLoginFailure();
                }
            }
        };
        LoginService.Util.getInstance().getLogin(callback);
    }

    private void getLoginAuthorizations(final LoginWindow loginWindow) {
        AsyncCallback<Map<Function, Boolean>> callback = new AsyncCallback<Map<Function, Boolean>>() {
            @Override
            public void onFailure(Throwable caught) {
                WebPasswordSafe.handleServerFailure(caught);
            }

            @Override
            public void onSuccess(Map<Function, Boolean> result) {
                getClientModel().setAuthorizations(result);
                getLoginReports(loginWindow);
            }
        };
        LoginService.Util.getInstance().getLoginAuthorizations(null, callback);
    }

    private void getLoginReports(final LoginWindow loginWindow) {
        AsyncCallback<List<Map<String, Object>>> callback = new AsyncCallback<List<Map<String, Object>>>() {
            @Override
            public void onFailure(Throwable caught) {
                WebPasswordSafe.handleServerFailure(caught);
            }

            @Override
            public void onSuccess(List<Map<String, Object>> result) {
                getClientModel().setAvailableReports(result);
                refreshLoginStatus();
                loginWindow.doGetLoginSuccess();
            }
        };
        LoginService.Util.getInstance().getLoginReports(callback);
    }

    private void getSystemSettings(final LoginWindow loginWindow) {
        AsyncCallback<SystemSettings> callback = new AsyncCallback<SystemSettings>() {
            @Override
            public void onFailure(Throwable caught) {
                WebPasswordSafe.handleServerFailure(caught);
            }

            @Override
            public void onSuccess(SystemSettings result) {
                clientSessionUtil.setSystemSettings(result);
                doGetLoggedInUser(loginWindow);
            }
        };
        LoginService.Util.getInstance().getSystemSettings(callback);
    }

    private void doLogout() {
        AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>() {
            @Override
            public void onFailure(Throwable caught) {
                WebPasswordSafe.handleServerFailure(caught);
            }

            @Override
            public void onSuccess(Boolean result) {
                if (result) {
                    clientSessionUtil.getLoggedInUser().setUsername("");
                    clientSessionUtil.setLoggedIn(false);
                    String logoutUrl = clientSessionUtil.getSystemSettings().getLogoutUrl();
                    if (logoutUrl.equals("")) {
                        Window.Location.reload();
                    } else {
                        logoutUrl = logoutUrl.replace("$1", URL.encodeQueryString(GWT.getHostPageBaseURL()));
                        Window.Location.replace(logoutUrl);
                    }
                }
            }
        };
        LoginService.Util.getInstance().logout(callback);
    }

    private void displayLoginDialog() {
        new LoginDialog(this).show();
    }

    private void displayUserDialog(User user) {
        new UserDialog(user).show();
    }

    @Override
    public ClientSessionUtil getClientModel() {
        return clientSessionUtil;
    }

    @Override
    public void doGetLoginSuccess() {
        Info.display(textMessages.status(),
                textMessages.loggedIn(Format.htmlEncode(getClientModel().getLoggedInUser().getUsername())));
    }

    @Override
    public void doGetLoginFailure() {
        String bypassSSO = Window.Location.getParameter("bypassSSO");
        bypassSSO = (bypassSSO == null) ? "false" : bypassSSO;
        if (clientSessionUtil.getSystemSettings().isSsoEnabled() && !bypassSSO.equals("true")) {
            // sso enabled and not bypass, redirect to sso filtered page
            Window.Location.replace(GWT.getHostPageBaseURL() + "sso");
        } else {
            displayLoginDialog();
        }
    }

    private void doShowAbout() {
        new AboutDialog().show();
    }

    private void doShowHelp() {
        Window.open(GWT.getHostPageBaseURL() + Constants.URL_HELP, "_blank", "");
    }

    private class EditUserListener implements UserListener {
        @Override
        public void doUsersChosen(List<User> users) {
            if (users.size() > 0) {
                AsyncCallback<User> callback = new AsyncCallback<User>() {
                    @Override
                    public void onFailure(Throwable caught) {
                        WebPasswordSafe.handleServerFailure(caught);
                    }

                    @Override
                    public void onSuccess(User result) {
                        displayUserDialog(result);
                    }
                };
                UserService.Util.getInstance().getUserWithGroups(users.get(0).getId(), callback);
            }
        }
    }

    private class EditGroupListener implements GroupListener {
        @Override
        public void doGroupsChosen(List<Group> groups) {
            if (groups.size() > 0) {
                AsyncCallback<Group> callback = new AsyncCallback<Group>() {
                    @Override
                    public void onFailure(Throwable caught) {
                        WebPasswordSafe.handleServerFailure(caught);
                    }

                    @Override
                    public void onSuccess(Group result) {
                        displayGroupDialog(result);
                    }
                };
                UserService.Util.getInstance().getGroupWithUsers(groups.get(0).getId(), callback);
            }
        }
    }

    private class EditTemplateListener implements TemplateListener {
        @Override
        public void doTemplatesChosen(List<Template> templates) {
            if (templates.size() > 0) {
                AsyncCallback<Template> callback = new AsyncCallback<Template>() {
                    @Override
                    public void onFailure(Throwable caught) {
                        WebPasswordSafe.handleServerFailure(caught);
                    }

                    @Override
                    public void onSuccess(Template result) {
                        displayTemplateDialog(result);
                    }
                };
                PasswordService.Util.getInstance().getTemplateWithDetails(templates.get(0).getId(), callback);
            }
        }
    }

    //// public static methods...

    public static void handleServerFailure(Throwable caught) {
        handleServerFailure(caught, false);
    }

    public static void handleServerFailure(Throwable caught, boolean showDetails) {
        String message = textMessages.sessionTimeout() + (showDetails ? "<br>" + caught.getMessage() : "");
        MessageBox.alert(textMessages.error(), message, new ServerErrorListener());
    }

}