package com.amazonaws.eclipse.codedeploy.deploy.wizard.page; import static com.amazonaws.eclipse.core.ui.wizards.WizardWidgetFactory.newCombo; import static com.amazonaws.eclipse.core.ui.wizards.WizardWidgetFactory.newFillingLabel; import static com.amazonaws.eclipse.core.ui.wizards.WizardWidgetFactory.newGroup; import static com.amazonaws.eclipse.core.ui.wizards.WizardWidgetFactory.newLink; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.core.databinding.AggregateValidationStatus; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.beans.PojoObservables; import org.eclipse.core.databinding.observable.ChangeEvent; import org.eclipse.core.databinding.observable.IChangeListener; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.databinding.observable.value.WritableValue; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.databinding.swt.ISWTObservableValue; import org.eclipse.jface.databinding.swt.SWTObservables; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Link; import org.eclipse.ui.statushandlers.StatusManager; import com.amazonaws.eclipse.codedeploy.CodeDeployPlugin; import com.amazonaws.eclipse.codedeploy.ServiceAPIUtils; import com.amazonaws.eclipse.codedeploy.UrlConstants; import com.amazonaws.eclipse.codedeploy.deploy.wizard.model.DeployProjectToCodeDeployWizardDataModel; import com.amazonaws.eclipse.core.AwsToolkitCore; import com.amazonaws.eclipse.core.regions.Region; import com.amazonaws.eclipse.core.regions.RegionUtils; import com.amazonaws.eclipse.core.regions.ServiceAbbreviations; import com.amazonaws.eclipse.core.ui.CancelableThread; import com.amazonaws.eclipse.core.ui.WebLinkListener; import com.amazonaws.eclipse.databinding.BooleanValidator; import com.amazonaws.eclipse.databinding.ChainValidator; import com.amazonaws.services.codedeploy.AmazonCodeDeploy; public class DeploymentGroupSelectionPage extends WizardPageWithOnEnterHook{ /* Data model and binding */ private final DeployProjectToCodeDeployWizardDataModel dataModel; private final DataBindingContext bindingContext; private final AggregateValidationStatus aggregateValidationStatus; private IObservableValue applicationSelected = new WritableValue(); private IObservableValue deploymentGroupSelected = new WritableValue(); /* UI widgets */ // Select region private Combo regionCombo; // Select application private Combo applicationNameCombo; private Link applicationSelectionMessageLabel; // Select deployment-group private Combo deploymentGroupNameCombo; private Link deploymentGroupSelectionMessageLabel; /* Other */ private AmazonCodeDeploy codeDeployClient; private LoadApplicationsThread loadApplicationsThread; private LoadDeploymentGroupsThread loadDeploymentGroupsThread; private final WebLinkListener webLinkListener = new WebLinkListener(); /* Constants */ private static final String LOADING = "Loading..."; private static final String NONE_FOUND = "None found"; public DeploymentGroupSelectionPage(DeployProjectToCodeDeployWizardDataModel dataModel) { super("Select the target Application and Deployment Group"); setTitle("Select the target Application and Deployment Group"); setDescription(""); this.dataModel = dataModel; this.bindingContext = new DataBindingContext(); this.aggregateValidationStatus = new AggregateValidationStatus( bindingContext, AggregateValidationStatus.MAX_SEVERITY); initializeValidators(); } public void createControl(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout(1, false)); createRegionSection(composite); createApplicationSelection(composite); createDeploymentGroupSelection(composite); onRegionChange(); bindControls(); setControl(composite); setPageComplete(false); } public void onEnterPage() { } /* Private interface */ private void initializeValidators() { // Bind the validation status to the wizard page message aggregateValidationStatus.addChangeListener(new IChangeListener() { public void handleChange(ChangeEvent arg0) { Object value = aggregateValidationStatus.getValue(); if (value instanceof IStatus == false) return; IStatus status = (IStatus)value; boolean success = (status.getSeverity() == IStatus.OK); setPageComplete(success); if (success) { setMessage("", IStatus.OK); } else { setMessage(status.getMessage(), IStatus.ERROR); } } }); // Validation status providers bindingContext.addValidationStatusProvider(new ChainValidator<Boolean>( applicationSelected, new BooleanValidator("Please select the application"))); bindingContext.addValidationStatusProvider(new ChainValidator<Boolean>( deploymentGroupSelected, new BooleanValidator("Please select the deployment group"))); } private void bindControls() { ISWTObservableValue applicationNameComboObservable = SWTObservables .observeSelection(applicationNameCombo); bindingContext.bindValue( applicationNameComboObservable, PojoObservables.observeValue( dataModel, DeployProjectToCodeDeployWizardDataModel.APPLICATION_NAME_PROPERTY)); ISWTObservableValue deploymentGroupNameComboObservable = SWTObservables .observeSelection(deploymentGroupNameCombo); bindingContext.bindValue( deploymentGroupNameComboObservable, PojoObservables.observeValue( dataModel, DeployProjectToCodeDeployWizardDataModel.DEPLOYMENT_GROUP_NAME_PROPERTY)); } private void createRegionSection(Composite composite) { Group regionGroup = newGroup(composite, "Select AWS Region"); regionGroup.setLayout(new GridLayout(1, false)); regionCombo = newCombo(regionGroup); for (Region region : RegionUtils.getRegionsForService(ServiceAbbreviations.CODE_DEPLOY)) { regionCombo.add(region.getName()); regionCombo.setData(region.getName(), region); } // Find the default region selection Region selectedRegion = dataModel.getRegion(); if (selectedRegion == null) { if ( RegionUtils.isServiceSupportedInCurrentRegion(ServiceAbbreviations.CODE_DEPLOY) ) { selectedRegion = RegionUtils.getCurrentRegion(); } else { selectedRegion = RegionUtils.getRegion(CodeDeployPlugin.DEFAULT_REGION); } } regionCombo.setText(selectedRegion.getName()); regionCombo.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { onRegionChange(); } }); newFillingLabel(regionGroup, "Select the AWS region where your CodeDeploy application was created."); } private void createApplicationSelection(Composite composite) { Group applicationGroup = newGroup(composite, "Select CodeDeploy application:"); applicationGroup.setLayout(new GridLayout(1, false)); applicationNameCombo = newCombo(applicationGroup); applicationNameCombo.setEnabled(false); applicationNameCombo.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { onApplicationSelectionChange(); } }); applicationSelectionMessageLabel = newLink(applicationGroup, webLinkListener, "", 1); } private void createDeploymentGroupSelection(Composite composite) { Group deploymentGroupSection = newGroup(composite, "Select CodeDeploy Deployment Group:"); deploymentGroupSection.setLayout(new GridLayout(1, false)); deploymentGroupNameCombo = newCombo(deploymentGroupSection); deploymentGroupNameCombo.setEnabled(false); deploymentGroupSelectionMessageLabel = newLink(deploymentGroupSection, webLinkListener, "", 1); } private void onRegionChange() { Region region = (Region)regionCombo.getData(regionCombo.getText()); String endpoint = region.getServiceEndpoints() .get(ServiceAbbreviations.CODE_DEPLOY); codeDeployClient = AwsToolkitCore.getClientFactory() .getCodeDeployClientByEndpoint(endpoint); dataModel.setRegion(region); refreshApplications(); } private void onApplicationSelectionChange() { if (applicationSelected.getValue().equals(Boolean.TRUE)) { refreshDeploymentGroups(); } } private void refreshApplications() { applicationSelected.setValue(false); if (applicationNameCombo != null) { applicationNameCombo.setItems(new String[] {LOADING}); applicationNameCombo.select(0); } if (applicationSelectionMessageLabel != null) { applicationSelectionMessageLabel.setText(""); } CancelableThread.cancelThread(loadApplicationsThread); loadApplicationsThread = new LoadApplicationsThread(); loadApplicationsThread.start(); } private void refreshDeploymentGroups() { deploymentGroupSelected.setValue(false); if (deploymentGroupNameCombo != null) { deploymentGroupNameCombo.setItems(new String[] {LOADING}); deploymentGroupNameCombo.select(0); } if (deploymentGroupSelectionMessageLabel != null) { deploymentGroupSelectionMessageLabel.setText(""); } CancelableThread.cancelThread(loadDeploymentGroupsThread); loadDeploymentGroupsThread = new LoadDeploymentGroupsThread(); loadDeploymentGroupsThread.start(); } private final class LoadApplicationsThread extends CancelableThread { @Override public void run() { final List<String> appNames = new ArrayList<String>(); try { appNames.addAll(ServiceAPIUtils.getAllApplicationNames(codeDeployClient)); Collections.sort(appNames); } catch (Exception e) { CodeDeployPlugin.getDefault().reportException( "Unable to load existing applications.", e); setRunning(false); return; } Display.getDefault().asyncExec(new Runnable() { public void run() { try { synchronized (LoadApplicationsThread.this) { if ( !isCanceled() ) { applicationNameCombo.removeAll(); for ( String appName : appNames ) { applicationNameCombo.add(appName); } if ( appNames.size() > 0 ) { applicationNameCombo.setEnabled(true); applicationNameCombo.select(0); applicationSelected.setValue(true); refreshDeploymentGroups(); } else { applicationNameCombo.setEnabled(false); applicationNameCombo.setItems(new String[] { NONE_FOUND}); applicationNameCombo.select(0); applicationSelected.setValue(false); applicationSelectionMessageLabel.setText( "No application is found in this region. " + "Please create a new CodeDeploy application via " + "<a href=\"" + String.format(UrlConstants.CODE_DEPLOY_CONSOLE_URL_FORMAT, dataModel.getRegion().getId()) + "\">AWS Console</a> before making a deployment"); deploymentGroupNameCombo.setEnabled(false); deploymentGroupNameCombo.setItems(new String[0]); deploymentGroupSelected.setValue(false); } // Re-calculate UI layout ((Composite)getControl()).layout(); } } } finally { setRunning(false); } } }); } } private final class LoadDeploymentGroupsThread extends CancelableThread { @Override public void run() { final List<String> deployGroupNames = new ArrayList<String>(); try { String appName = dataModel.getApplicationName(); deployGroupNames.addAll(ServiceAPIUtils .getAllDeploymentGroupNames(codeDeployClient, appName)); Collections.sort(deployGroupNames); } catch (Exception e) { Status status = new Status(Status.ERROR, CodeDeployPlugin.PLUGIN_ID, "Unable to load existing deployment groups: " + e.getMessage(), e); StatusManager.getManager().handle(status, StatusManager.SHOW); setRunning(false); return; } Display.getDefault().asyncExec(new Runnable() { public void run() { try { synchronized (LoadDeploymentGroupsThread.this) { if ( !isCanceled() ) { deploymentGroupNameCombo.removeAll(); for ( String deployGroupName : deployGroupNames ) { deploymentGroupNameCombo.add(deployGroupName); } if ( deployGroupNames.size() > 0 ) { deploymentGroupNameCombo.select(0); deploymentGroupNameCombo.setEnabled(true); deploymentGroupSelected.setValue(true); } else { deploymentGroupNameCombo.setEnabled(false); deploymentGroupNameCombo.setItems(new String[] { NONE_FOUND}); deploymentGroupNameCombo.select(0); deploymentGroupSelected.setValue(false); deploymentGroupSelectionMessageLabel.setText( "No deployment group is found. " + "Please create a new deployment group via " + "<a href=\"" + String.format(UrlConstants.CODE_DEPLOY_CONSOLE_URL_FORMAT, dataModel.getRegion().getId()) + "\">AWS Console</a> before making a deployment"); } // Re-calculate UI layout ((Composite)getControl()).layout(); } } } finally { setRunning(false); } } }); } } }