org.cloudfoundry.ide.eclipse.server.ui.internal.wizards.CloudFoundryServiceWizardPage.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.ide.eclipse.server.ui.internal.wizards.CloudFoundryServiceWizardPage.java

Source

/*******************************************************************************
 * Copyright (c) 2014, 2015 Pivotal Software Inc and IBM Corporation. 
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License, 
 * Version 2.0 (the "License"); you may not use this file except in compliance 
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *  
 * Contributors:
 *     Pivotal Software, Inc. - initial API and implementation
 *     IBM Corporation - Additions to services wizard
 *******************************************************************************/
package org.cloudfoundry.ide.eclipse.server.ui.internal.wizards;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.cloudfoundry.client.lib.domain.CloudService;
import org.cloudfoundry.client.lib.domain.CloudServiceOffering;
import org.cloudfoundry.ide.eclipse.server.core.internal.CloudFoundryServer;
import org.cloudfoundry.ide.eclipse.server.ui.internal.CloudFoundryImages;
import org.cloudfoundry.ide.eclipse.server.ui.internal.Logger;
import org.cloudfoundry.ide.eclipse.server.ui.internal.Messages;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.dialogs.IMessageProvider;
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.wizard.WizardPage;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.statushandlers.StatusManager;

public class CloudFoundryServiceWizardPage extends WizardPage {

    final CloudFoundryServiceWizard parent;

    private CloudFoundryServiceWizardPageLeftPanel leftPanel;
    private CloudFoundryServiceWizardPageRightPanel rightPanel;

    private CloudFoundryServer cloudServer;

    Composite topComp;

    /** Available services: these are the entries on the left-hand side of the wizard page */
    private List<AvailableService> availableServices;

    /** Retrieve the names of existing services in the space; these are the (bound or unbound) 
     * services that are already present in the account and are used for validation. */
    private List<String> existingCloudServiceNames = new ArrayList<String>();

    public CloudFoundryServiceWizardPage(CloudFoundryServer cloudServer, CloudFoundryServiceWizard parent) {
        super(CloudFoundryServiceWizardPage.class.getName());

        this.parent = parent;
        this.cloudServer = cloudServer;

        setTitle(Messages.CloudFoundryServiceWizardPage_TTILE_SERVICE_CONFIG);
        setDescription(Messages.CloudFoundryServiceWizardPage_TEXT_FINISH);

        ImageDescriptor banner = CloudFoundryImages
                .getWizardBanner(cloudServer.getServer().getServerType().getId());
        if (banner != null) {
            setImageDescriptor(banner);
        }

        // Acquire the services list in a UI-thread-safe, cancellable job. 
        availableServices = updateConfiguration();
        if (availableServices == null && parent.getParent() != null) {
            // User cancelled the service, so close the dialog.
            parent.getParent().close();
            return;
        }

    }

    @Override
    public void setVisible(boolean isVis) {
        super.setVisible(isVis);

        leftPanel.createInnerLayoutList(availableServices, leftPanel.layoutList);

    }

    /** Returns the list of available services, or null if the user cancelled the monitor. */
    private List<AvailableService> updateConfiguration() {
        final List<AvailableService> result = new ArrayList<AvailableService>();

        try {

            final GetServiceOfferingsRunnable runnable = new GetServiceOfferingsRunnable();

            // Begin retrieving the service offerings
            ProgressMonitorDialog monitorDlg = new ProgressMonitorDialog(getShell());
            monitorDlg.run(true, true, runnable);

            GetServiceResult getServiceResult = runnable.getGetServiceOperationResult();

            if (getServiceResult == GetServiceResult.SUCCESS) {
                if (runnable.getServiceOfferingResult() != null) {

                    if (runnable.getServiceOfferingResult().size() > 0) {

                        int index = 0;
                        for (CloudServiceOffering o : runnable.getServiceOfferingResult()) {

                            result.add(new AvailableService(o.getName(), o.getDescription(), index, o));
                            index++;
                        }
                    } else {
                        // Operation succeeded, but no services are available.

                        MessageDialog.openWarning(getShell(),
                                Messages.CloudFoundryServiceWizard_NO_SERVICES_AVAILABLE_TITLE,
                                Messages.CloudFoundryServiceWizard_NO_SERVICES_AVAILABLE_BODY);

                        return null;
                    }
                }

            } else if (getServiceResult == GetServiceResult.ERROR) {
                // Error is handled by the exception and by the runnable
                return null;
            } else {
                // If the user cancelled service acquisition, then just return null.
                return null;
            }

        } catch (InvocationTargetException e) {
            Throwable ex = e.getCause() != null ? e.getCause() : e;
            String msg = ex.getMessage();

            // Use a generic message if the exception did not provide one.
            if (msg == null || msg.trim().length() == 0) {
                msg = Messages.CloudFoundryServiceWizardPage_ERROR_CONFIG_RETRIVE_SEE_LOG_FOR_DETAILS;
            }

            IStatus status = cloudServer
                    .error(NLS.bind(Messages.CloudFoundryServiceWizardPage_ERROR_CONFIG_RETRIVE, msg), e);
            StatusManager.getManager().handle(status, StatusManager.LOG);
            setMessage(status.getMessage(), IMessageProvider.ERROR);
        } catch (InterruptedException e) {
            if (Logger.WARNING) {
                Logger.println(Logger.WARNING_LEVEL, this, "updateConfiguration", //$NON-NLS-1$
                        "Failed to load the list of available services."); //$NON-NLS-1$
            }
        }

        return result;
    }

    @Override
    public void createControl(Composite parent) {

        Composite main = new Composite(parent, SWT.NONE);

        GridLayout gridLayout = new GridLayout(1, true);
        main.setLayout(gridLayout);
        topComp = main;

        GridData gd;

        Composite central = new Composite(main, SWT.NONE);
        gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.horizontalSpan = 1;
        gd.verticalIndent = 10;
        central.setLayoutData(gd);

        FillLayout fillLayout = new FillLayout();
        fillLayout.type = SWT.HORIZONTAL;
        fillLayout.marginHeight = 0;
        fillLayout.marginWidth = 0;
        fillLayout.spacing = 15;
        central.setLayout(fillLayout);

        leftPanel = new CloudFoundryServiceWizardPageLeftPanel(this);
        leftPanel.createMainWindowComposite(central);

        rightPanel = new CloudFoundryServiceWizardPageRightPanel(this);
        rightPanel.createMainWindowComposite(central);

        // Now that the panel is created, pass the retrieved names to the right panel for validation
        rightPanel.setExistingServicesNames(existingCloudServiceNames);

        setControl(main);
    }

    public List<CloudService> getServices() {

        List<CloudService> result = new ArrayList<CloudService>();

        List<List<ServiceInstance>> newServices = rightPanel.getServiceInstances();
        if (newServices != null) {

            for (List<ServiceInstance> instances : newServices) {

                for (ServiceInstance instance : instances) {

                    result.add(instance.convertToLocalService());
                }
            }
        }

        return result;
    }

    public CloudFoundryServer getCloudServer() {
        return cloudServer;
    }

    @Override
    public void dispose() {
        super.dispose();

        if (leftPanel != null) {
            leftPanel.dispose();
        }
    }

    protected CloudFoundryServiceWizardPageRightPanel getRight() {
        return rightPanel;
    }

    private static enum GetServiceResult {
        INITIAL, SUCCESS, USER_CANCEL, ERROR
    };

    private class GetServiceOfferingsRunnable implements IRunnableWithProgress {

        private final List<CloudServiceOffering> serviceOfferingResult = new ArrayList<CloudServiceOffering>();

        private GetServiceResult result = GetServiceResult.INITIAL;

        public GetServiceOfferingsRunnable() {
        }

        @Override
        public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
            try {
                GetServiceOfferingsThread thread = new GetServiceOfferingsThread(monitor);
                thread.start();
                thread.waitForResult(monitor);

                List<CloudServiceOffering> serviceOfferings = null;
                if (thread.isOperationComplete()) {
                    if (thread.getException() != null) {
                        throw thread.getException();
                    } else {
                        serviceOfferings = thread.getServiceOfferings();
                    }
                } else {
                    result = GetServiceResult.USER_CANCEL;
                    // User cancelled.
                    return;
                }

                Collections.sort(serviceOfferings, new Comparator<CloudServiceOffering>() {
                    public int compare(CloudServiceOffering o1, CloudServiceOffering o2) {
                        return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase());
                    }
                });

                // Pivotal Tracker [77602464] - Leaving plans in order
                // received by server keeps them in pricing order from
                // low to high
                // sortServicePlans(serviceOfferings);
                serviceOfferingResult.addAll(serviceOfferings);

                // Retrieve the names of existing services in the space
                List<CloudService> allServices = cloudServer.getBehaviour().getServices(monitor);
                if (allServices != null) {
                    for (CloudService existingService : allServices) {
                        String name = existingService.getName().toLowerCase();

                        if (!existingCloudServiceNames.contains(name)) {
                            existingCloudServiceNames.add(name);
                        }
                    }
                }

                result = GetServiceResult.SUCCESS;

            } catch (OperationCanceledException e) {
                result = GetServiceResult.USER_CANCEL;
                throw new InterruptedException();

            } catch (Throwable e) {
                result = GetServiceResult.ERROR;
                throw new InvocationTargetException(e);
            } finally {
                monitor.done();
            }
        }

        public GetServiceResult getGetServiceOperationResult() {
            return result;
        }

        public List<CloudServiceOffering> getServiceOfferingResult() {
            return serviceOfferingResult;
        }
    }

    /** Retrieve the service offerings independently of the requesting job; call waitForResult w/ a progress monitor and
     * get(Exception/ServiceOfferings) for result.  */
    private class GetServiceOfferingsThread extends Thread {

        private final IProgressMonitor monitor;

        private final Object lock = new Object();

        private boolean operationComplete = false; // locked by lock
        private Throwable exception; // locked by lock
        private List<CloudServiceOffering> serviceOfferings; // locked by lock

        public GetServiceOfferingsThread(IProgressMonitor monitor) {
            setName(GetServiceOfferingsThread.class.getName());
            setDaemon(true);
            this.monitor = monitor;
        }

        @Override
        public void run() {
            try {

                monitor.beginTask(Messages.CloudFoundryServiceWizardPage_GETTING_AVAILABLE_SERVICES,
                        IProgressMonitor.UNKNOWN);

                List<CloudServiceOffering> localServiceOfferings = cloudServer.getBehaviour()
                        .getServiceOfferings(new NullProgressMonitor());

                synchronized (lock) {
                    serviceOfferings = localServiceOfferings;
                }
            } catch (Throwable e) {
                synchronized (lock) {
                    this.exception = e;
                }
            } finally {
                synchronized (lock) {
                    operationComplete = true;
                    lock.notify();
                }
            }
        }

        public void waitForResult(IProgressMonitor monitor) {
            try {
                // Wait for cancel or completion.
                while (!monitor.isCanceled()) {
                    synchronized (lock) {
                        lock.wait(100);

                        if (operationComplete) {
                            break;
                        }
                    }

                }
            } catch (InterruptedException ex) {
                return;
            }
        }

        public Throwable getException() {
            synchronized (lock) {
                return exception;
            }
        }

        public List<CloudServiceOffering> getServiceOfferings() {
            synchronized (lock) {
                return serviceOfferings;
            }
        }

        public boolean isOperationComplete() {
            synchronized (lock) {
                return operationComplete;
            }
        }
    }
}