org.jboss.tools.modeshape.rest.views.ModeShapeContentProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.modeshape.rest.views.ModeShapeContentProvider.java

Source

/*
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.
 *
 * This software is made available by Red Hat, Inc. under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution and is
 * available at http://www.eclipse.org/legal/epl-v10.html.
 *
 * See the AUTHORS.txt file in the distribution for a full listing of
 * individual contributors.
 */
package org.jboss.tools.modeshape.rest.views;

import static org.jboss.tools.modeshape.rest.IUiConstants.PUBLISHED_OVERLAY_IMAGE;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jface.viewers.ILazyTreeContentProvider;
import org.eclipse.jface.viewers.ILightweightLabelDecorator;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IDecoratorManager;
import org.jboss.tools.modeshape.rest.Activator;
import org.jboss.tools.modeshape.rest.IServerRegistryListener;
import org.jboss.tools.modeshape.rest.IUiConstants;
import org.jboss.tools.modeshape.rest.PublishedResourceHelper;
import org.jboss.tools.modeshape.rest.RestClientI18n;
import org.jboss.tools.modeshape.rest.ServerManager;
import org.jboss.tools.modeshape.rest.ServerRegistryEvent;
import org.jboss.tools.modeshape.rest.domain.ModeShapeDomainObject;
import org.jboss.tools.modeshape.rest.domain.ModeShapeRepository;
import org.jboss.tools.modeshape.rest.domain.ModeShapeServer;
import org.jboss.tools.modeshape.rest.domain.ModeShapeWorkspace;
import org.jboss.tools.modeshape.rest.domain.WorkspaceArea;
import org.modeshape.common.annotation.GuardedBy;

/**
 * The <code>ModeShapeContentProvider</code> is a content and label provider for the repositories. This class <strong>MUST</strong>
 * be registered, and then unregistered, to receive server registry events.
 */
public final class ModeShapeContentProvider extends ColumnLabelProvider
        implements ILightweightLabelDecorator, IServerRegistryListener, ILazyTreeContentProvider {

    /**
     * The decorator ID.
     */
    private static final String ID = "org.jboss.tools.modeshape.rest.decorator"; //$NON-NLS-1$

    /**
     * If a server connection cannot be established, wait this amount of time before trying again.
     */
    private static final long RETRY_DURATION = 5000;

    /**
     * Indicates if the Eclipse lazy content provider has already called this provider. This occurs when the associated viewer of
     * this provider has been shown once or if the Eclipse window loses focus.
     */
    private static boolean _alreadyCalledByFramework;

    /**
     * Servers that a connection can't be established. Value is the last time a establishing a connection was tried.
     */
    @GuardedBy("offlineServersLock")
    private final static Map<ModeShapeServer, Long> _offlineServerMap = new HashMap<ModeShapeServer, Long>();

    /**
     * Lock used for when accessing the offline server map. The map will be accessed in different threads as the decorator runs in
     * its own thread (not the UI thread).
     */
    private final static ReadWriteLock _offlineServersLock = new ReentrantReadWriteLock();

    /**
     * @return the decorator
     */
    public static ModeShapeContentProvider getDecorator() {
        final IDecoratorManager decoratorMgr = Activator.getDefault().getWorkbench().getDecoratorManager();

        if (decoratorMgr.getEnabled(ID)) {
            return (ModeShapeContentProvider) decoratorMgr.getBaseLabelProvider(ID);
        }

        return null;
    }

    /**
     * The server manager where the server registry is managed.
     */
    private ServerManager serverManager;

    private TreeViewer viewer;

    /**
     * @param server the server that is offline
     */
    void addOfflineServer(final ModeShapeServer server) {
        if (this.viewer != null) {
            this.viewer.setHasChildren(server, false); // get rid of the expansion button
        }

        try {
            _offlineServersLock.writeLock().lock();
            _offlineServerMap.put(server, System.currentTimeMillis());
            refresh(server);
        } finally {
            _offlineServersLock.writeLock().unlock();
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.ILightweightLabelDecorator#decorate(java.lang.Object, org.eclipse.jface.viewers.IDecoration)
     */
    @Override
    public void decorate(final Object element, final IDecoration decoration) {
        ImageDescriptor overlay = null;
        final Display display = Display.getDefault();

        if (display.isDisposed()) {
            return;
        }

        if (element instanceof ModeShapeServer) {
            final ModeShapeServer server = (ModeShapeServer) element;

            // if server is offline then decorate with error overlay
            try {
                _offlineServersLock.readLock().lock();

                if (_offlineServerMap.containsKey(server)) {
                    overlay = Activator.getDefault().getImageDescriptor(IUiConstants.ERROR_OVERLAY_IMAGE);
                }
            } finally {
                _offlineServersLock.readLock().unlock();
            }
        } else if (element instanceof IFile) {
            final IFile file = (IFile) element;

            if (file.exists() && !file.isHidden()
                    && new PublishedResourceHelper(getServerManager()).isPublished((IFile) element)) {
                overlay = Activator.getDefault().getImageDescriptor(PUBLISHED_OVERLAY_IMAGE);
            }
        }

        if (overlay != null) {
            decoration.addOverlay(overlay);
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.IContentProvider#dispose()
     */
    @Override
    public void dispose() {
        // nothing to do
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
     */
    @Override
    public Image getImage(final Object element) {
        return Activator.getDefault().getImage(element);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#getParent(java.lang.Object)
     */
    @Override
    public Object getParent(final Object element) {
        assert (element instanceof ModeShapeDomainObject);

        if (element instanceof WorkspaceArea) {
            return ((WorkspaceArea) element).getWorkspace();
        }

        if (element instanceof ModeShapeWorkspace) {
            return ((ModeShapeWorkspace) element).getRepository();
        }

        if (element instanceof ModeShapeRepository) {
            return ((ModeShapeRepository) element).getServer();
        }

        if (element instanceof ModeShapeServer) {
            return getServerManager();
        }

        assert false : "unknown ModeShapeDomainObject=" + element.getClass(); //$NON-NLS-1$
        return null;
    }

    ServerManager getServerManager() {
        if (this.serverManager == null) {
            this.serverManager = Activator.getDefault().getServerManager();
        }

        return this.serverManager;
    }

    Shell getShell() {
        return this.viewer.getTree().getShell();
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
     */
    @Override
    public String getText(final Object element) {
        assert (element instanceof ModeShapeDomainObject);
        return ((ModeShapeDomainObject) element).getName();
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipImage(java.lang.Object)
     */
    @Override
    public Image getToolTipImage(final Object object) {
        return getImage(object);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipText(java.lang.Object)
     */
    @Override
    public String getToolTipText(final Object element) {
        if (element instanceof ModeShapeDomainObject) {
            return ((ModeShapeDomainObject) element).getShortDescription();
        }

        return super.getToolTipText(element);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipTimeDisplayed(java.lang.Object)
     */
    @Override
    public int getToolTipTimeDisplayed(final Object object) {
        return 3000;
    }

    TreeViewer getViewer() {
        return this.viewer;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object,
     *      java.lang.Object)
     */
    @Override
    public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
        // nothing to do
    }

    /**
     * Determines if a try to connect to a server should be done based on the last time a try was done and failed.
     *
     * @param server the server being checked
     * @return <code>true</code> if it is OK to try and connect
     */
    private boolean isOkToConnect(final ModeShapeServer server) {
        boolean check = false; // check map for time

        try {
            _offlineServersLock.readLock().lock();
            check = _offlineServerMap.containsKey(server);
        } finally {
            _offlineServersLock.readLock().unlock();
        }

        if (check) {
            try {
                _offlineServersLock.writeLock().lock();

                if (_offlineServerMap.containsKey(server)) {
                    final long checkTime = _offlineServerMap.get(server);

                    // OK to try and connect if last failed attempt was too long ago
                    if ((System.currentTimeMillis() - checkTime) > RETRY_DURATION) {
                        _offlineServerMap.remove(server);
                        refresh(server);
                        return true;
                    }

                    // don't try and connect because we just tried and failed
                    return false;
                }
            } finally {
                _offlineServersLock.writeLock().unlock();
            }
        }

        // OK to try and connect
        return true;
    }

    public void refresh(final Object element) {
        final Display display = Display.getDefault();

        if (display.isDisposed()) {
            return;
        }

        display.asyncExec(new Runnable() {
            /**
             * {@inheritDoc}
             *
             * @see java.lang.Runnable#run()
             */
            @SuppressWarnings("synthetic-access")
            @Override
            public void run() {
                fireLabelProviderChanged(new LabelProviderChangedEvent(ModeShapeContentProvider.this, element));
            }
        });
    }

    private void run(final ServerOperation op, final boolean enforceNonEmptyPassword) {
        try {
            final ModeShapeServer server = op.getServer();

            if (enforceNonEmptyPassword && ((server.getPassword() == null) || server.getPassword().isEmpty())) {
                if (MessageDialog.openQuestion(getShell(), RestClientI18n.missingServerPasswordDialogTitle,
                        RestClientI18n.missingServerPasswordDialogMsg)) {
                    final NewPasswordDialog dialog = new NewPasswordDialog(getShell());

                    if (dialog.open() == Window.OK) {
                        getServerManager().updateServer(server, new ModeShapeServer(server.getOriginalUrl(),
                                server.getUser(), dialog.getNewPassword(), server.isPasswordBeingPersisted()));

                        // need to obtain changed server from server manager as servers are not mutable
                        for (final ModeShapeServer registeredServer : getServerManager().getServers()) {
                            if (registeredServer.hasSameKey(server)) {
                                op.setUpdatedServer(registeredServer);
                                break;
                            }
                        }
                    }
                }
            }

            final ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell()) {

                /**
                 * {@inheritDoc}
                 *
                 * @see org.eclipse.jface.dialogs.ProgressMonitorDialog#configureShell(org.eclipse.swt.widgets.Shell)
                 */
                @Override
                protected void configureShell(final Shell shell) {
                    super.configureShell(shell);
                    shell.setText(RestClientI18n.requestDialogTitle);
                }
            };

            dialog.run(true, false, op);
        } catch (final InvocationTargetException e) {
            // should not happen as ServerOperation handles this but just in case
            if (op.getUpdatedServer() == null) {
                addOfflineServer(op.getServer());
            } else {
                addOfflineServer(op.getUpdatedServer());
            }

            final org.eclipse.core.runtime.Status error = new org.eclipse.core.runtime.Status(IStatus.ERROR,
                    IUiConstants.PLUGIN_ID, RestClientI18n.runningServerRequestErrorMsg, e.getCause());
            ErrorDialog.openError(getShell(), RestClientI18n.runningServerRequestErrorDialogTitle,
                    RestClientI18n.runningServerRequestErrorDialogMsg, error);
        } catch (final InterruptedException e) {
            // won't happen as runnable is not cancelable
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.jboss.tools.modeshape.rest.IServerRegistryListener#serverRegistryChanged(org.jboss.tools.modeshape.rest.ServerRegistryEvent)
     */
    @Override
    public Exception[] serverRegistryChanged(final ServerRegistryEvent event) {
        Exception[] errors = null;

        // only care about servers being removed or updated
        if (event.isRemove() || event.isUpdate()) {
            try {
                _offlineServersLock.writeLock().lock();
                _offlineServerMap.remove(event.getServer());
            } catch (final Exception e) {
                errors = new Exception[] { e };
            } finally {
                _offlineServersLock.writeLock().unlock();
            }
        }

        return errors;
    }

    void setViewer(final TreeViewer viewer) {
        this.viewer = viewer;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateChildCount(java.lang.Object, int)
     */
    @Override
    public void updateChildCount(final Object element, final int currentChildCount) {
        getServerManager(); // make sure server manager has been set

        if (element == this.serverManager) {
            final Collection<ModeShapeServer> servers = this.serverManager.getServers();

            if (servers.size() != currentChildCount) {
                this.viewer.setChildCount(element, servers.size());
            }

            if (_alreadyCalledByFramework) {
                updateElement(element, 0);
            } else {
                _alreadyCalledByFramework = true;
            }
        } else if (element instanceof ModeShapeServer) {
            final ModeShapeServer server = (ModeShapeServer) element;

            if (isOkToConnect(server)) {
                try {
                    final ServerOperation op = new ServerOperation(server) {

                        /**
                         * {@inheritDoc}
                         *
                         * @see org.jboss.tools.modeshape.rest.views.ModeShapeContentProvider.ServerOperation#doRun(org.eclipse.core.runtime.IProgressMonitor)
                         */
                        @Override
                        void doRun(final IProgressMonitor monitor)
                                throws InvocationTargetException, InterruptedException {
                            if (monitor.isCanceled()) {
                                throw new InterruptedException();
                            }

                            monitor.beginTask(RestClientI18n.runningRepositoriesQueryMsg, IProgressMonitor.UNKNOWN);
                            final ModeShapeServer serverToQuery = ((getUpdatedServer() == null) ? server
                                    : getUpdatedServer());

                            try {
                                final Collection<ModeShapeRepository> repositories = getServerManager()
                                        .getRepositories(serverToQuery);

                                if (repositories.size() != currentChildCount) {
                                    getViewer().setChildCount(serverToQuery, repositories.size());
                                }
                            } catch (final Exception e) {
                                throw new InvocationTargetException(e);
                            } finally {
                                monitor.done();
                            }
                        }

                        /**
                         * {@inheritDoc}
                         *
                         * @see org.jboss.tools.modeshape.rest.views.ModeShapeContentProvider.ServerOperation#getDisplay()
                         */
                        @Override
                        Display getDisplay() {
                            return getViewer().getTree().getDisplay();
                        }
                    };

                    run(op, true);
                } catch (final Exception e) {
                    addOfflineServer(server);
                }
            }
        } else if (element instanceof ModeShapeRepository) {
            final ModeShapeRepository repository = (ModeShapeRepository) element;

            if (isOkToConnect(repository.getServer())) {
                try {
                    final ServerOperation op = new ServerOperation(repository.getServer()) {

                        /**
                         * {@inheritDoc}
                         *
                         * @see org.jboss.tools.modeshape.rest.views.ModeShapeContentProvider.ServerOperation#doRun(org.eclipse.core.runtime.IProgressMonitor)
                         */
                        @Override
                        void doRun(final IProgressMonitor monitor)
                                throws InvocationTargetException, InterruptedException {
                            if (monitor.isCanceled()) {
                                throw new InterruptedException();
                            }

                            monitor.beginTask(RestClientI18n.runningWorkspacesQueryMsg, IProgressMonitor.UNKNOWN);

                            try {
                                final Collection<ModeShapeWorkspace> workspaces = getServerManager()
                                        .getWorkspaces(repository);

                                if (workspaces.size() != currentChildCount) {
                                    getViewer().setChildCount(repository, workspaces.size());
                                }
                            } catch (final Exception e) {
                                throw new InvocationTargetException(e);
                            } finally {
                                monitor.done();
                            }
                        }

                        /**
                         * {@inheritDoc}
                         *
                         * @see org.jboss.tools.modeshape.rest.views.ModeShapeContentProvider.ServerOperation#getDisplay()
                         */
                        @Override
                        Display getDisplay() {
                            return getViewer().getTree().getDisplay();
                        }
                    };

                    run(op, true);
                } catch (final Exception e) {
                    addOfflineServer(repository.getServer());
                }
            }
        } else if (element instanceof ModeShapeWorkspace) {
            final ModeShapeWorkspace workspace = (ModeShapeWorkspace) element;

            if (isOkToConnect(workspace.getServer())) {
                try {
                    final ServerOperation op = new ServerOperation(workspace.getServer()) {

                        /**
                         * {@inheritDoc}
                         *
                         * @see org.jboss.tools.modeshape.rest.views.ModeShapeContentProvider.ServerOperation#doRun(org.eclipse.core.runtime.IProgressMonitor)
                         */
                        @Override
                        void doRun(final IProgressMonitor monitor)
                                throws InvocationTargetException, InterruptedException {
                            if (monitor.isCanceled()) {
                                throw new InterruptedException();
                            }

                            monitor.beginTask(RestClientI18n.runningWorkspacesQueryMsg, IProgressMonitor.UNKNOWN);

                            try {
                                final WorkspaceArea[] workspaceAreas = getServerManager()
                                        .getWorkspaceAreas(workspace);

                                if (workspaceAreas.length != currentChildCount) {
                                    getViewer().setChildCount(workspace, workspaceAreas.length);
                                }
                            } catch (final Exception e) {
                                throw new InvocationTargetException(e);
                            } finally {
                                monitor.done();
                            }
                        }

                        /**
                         * {@inheritDoc}
                         *
                         * @see org.jboss.tools.modeshape.rest.views.ModeShapeContentProvider.ServerOperation#getDisplay()
                         */
                        @Override
                        Display getDisplay() {
                            return getViewer().getTree().getDisplay();
                        }
                    };

                    run(op, true);
                } catch (final Exception e) {
                    addOfflineServer(workspace.getServer());
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     *
     * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateElement(java.lang.Object, int)
     */
    @Override
    public void updateElement(final Object parent, final int index) {
        getServerManager(); // make sure server manager has been set

        if (parent == this.serverManager) {
            final ModeShapeServer server = new ArrayList<ModeShapeServer>(this.serverManager.getServers())
                    .get(index);
            this.viewer.replace(this.serverManager, index, server);
            this.viewer.setHasChildren(server, true);
        } else if (parent instanceof ModeShapeServer) {
            final ModeShapeServer server = (ModeShapeServer) parent;

            if (isOkToConnect(server)) {
                try {
                    final ModeShapeRepository repository = new ArrayList<ModeShapeRepository>(
                            this.serverManager.getRepositories(server)).get(index);
                    this.viewer.replace(server, index, repository);
                    this.viewer.setHasChildren(repository, true);
                } catch (final Exception e) {
                    addOfflineServer(server);
                }
            }
        } else if (parent instanceof ModeShapeRepository) {
            final ModeShapeRepository repository = (ModeShapeRepository) parent;

            if (isOkToConnect(repository.getServer())) {
                try {
                    final ModeShapeWorkspace workspace = new ArrayList<ModeShapeWorkspace>(
                            this.serverManager.getWorkspaces(repository)).get(index);
                    this.viewer.replace(repository, index, workspace);
                    this.viewer.setHasChildren(workspace, true);
                } catch (final Exception e) {
                    addOfflineServer(repository.getServer());
                }
            }
        } else if (parent instanceof ModeShapeWorkspace) {
            final ModeShapeWorkspace workspace = (ModeShapeWorkspace) parent;

            if (isOkToConnect(workspace.getServer())) {
                try {
                    final WorkspaceArea workspaceArea = Arrays
                            .asList(this.serverManager.getWorkspaceAreas(workspace)).get(index);
                    this.viewer.replace(workspace, index, workspaceArea);
                } catch (final Exception e) {
                    addOfflineServer(workspace.getServer());
                }
            }
        }
    }

    class NewPasswordDialog extends MessageDialog {

        private Button btnOk;
        private String newPassword = ""; //$NON-NLS-1$

        public NewPasswordDialog(final Shell parentShell) {
            super(parentShell, RestClientI18n.runningServerRequestNewPasswordDialogTitle, null,
                    RestClientI18n.runningServerRequestNewPasswordDialogMsg, MessageDialog.NONE,
                    new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
            setShellStyle(getShellStyle() | SWT.RESIZE);
        }

        /**
         * {@inheritDoc}
         *
         * @see org.eclipse.jface.dialogs.MessageDialog#createButton(org.eclipse.swt.widgets.Composite, int, java.lang.String,
         *      boolean)
         */
        @Override
        protected Button createButton(final Composite parent, final int id, final String label,
                final boolean defaultButton) {
            final Button btn = super.createButton(parent, id, label, defaultButton);

            if (id == IDialogConstants.OK_ID) {
                // disable OK button initially
                this.btnOk = btn;
                btn.setEnabled(false);
            }

            return btn;
        }

        /**
         * {@inheritDoc}
         *
         * @see org.eclipse.jface.dialogs.MessageDialog#createCustomArea(org.eclipse.swt.widgets.Composite)
         */
        @Override
        protected Control createCustomArea(final Composite parent) {
            final Composite panel = new Composite(parent, SWT.NONE);
            panel.setLayout(new GridLayout(2, false));
            panel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

            final Label lbl = new Label(panel, SWT.NONE);
            lbl.setText(RestClientI18n.serverPagePasswordLabel);

            final Text txt = new Text(panel, SWT.BORDER);
            txt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            txt.setToolTipText(RestClientI18n.serverPagePasswordToolTip);
            txt.addModifyListener(new ModifyListener() {

                /**
                 * {@inheritDoc}
                 *
                 * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
                 */
                @Override
                public void modifyText(final ModifyEvent e) {
                    handlePasswordChanged(((Text) e.widget).getText());
                }
            });

            return super.createCustomArea(parent);
        }

        public String getNewPassword() {
            return this.newPassword;
        }

        void handlePasswordChanged(final String newPassword) {
            this.newPassword = newPassword;

            // update OK button enablement
            final boolean enable = ((this.newPassword != null) && !this.newPassword.isEmpty());

            if (this.btnOk.getEnabled() != enable) {
                this.btnOk.setEnabled(enable);
            }
        }
    }

    abstract class ServerOperation implements IRunnableWithProgress {
        private ModeShapeServer updatedServer;
        private final ModeShapeServer server;

        public ServerOperation(final ModeShapeServer server) {
            this.server = server;
        }

        abstract void doRun(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException;

        abstract Display getDisplay();

        ModeShapeServer getServer() {
            return this.server;
        }

        ModeShapeServer getUpdatedServer() {
            return this.updatedServer;
        }

        /**
         * {@inheritDoc}
         *
         * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
         */
        @Override
        public final void run(final IProgressMonitor monitor) {
            getDisplay().asyncExec(new Runnable() {

                /**
                 * {@inheritDoc}
                 *
                 * @see java.lang.Runnable#run()
                 */
                @Override
                public void run() {
                    try {
                        doRun(monitor);
                    } catch (final InvocationTargetException e) {
                        if (getUpdatedServer() == null) {
                            addOfflineServer(getServer());
                        } else {
                            addOfflineServer(getUpdatedServer());
                        }

                        final org.eclipse.core.runtime.Status error = new org.eclipse.core.runtime.Status(
                                IStatus.ERROR, IUiConstants.PLUGIN_ID, RestClientI18n.runningServerRequestErrorMsg,
                                e.getCause());
                        ErrorDialog.openError(getShell(), RestClientI18n.runningServerRequestErrorDialogTitle,
                                RestClientI18n.runningServerRequestErrorDialogMsg, error);
                    } catch (final InterruptedException e) {
                        // should not happen has monitor is not cancelable
                    }
                }
            });
        }

        void setUpdatedServer(final ModeShapeServer updatedServer) {
            this.updatedServer = updatedServer;
        }
    }
}