package com.amazonaws.eclipse.opsworks.deploy.wizard.page;
import static com.amazonaws.eclipse.core.ui.wizards.WizardWidgetFactory.newCheckbox;
import static com.amazonaws.eclipse.core.ui.wizards.WizardWidgetFactory.newCombo;
import static com.amazonaws.eclipse.core.ui.wizards.WizardWidgetFactory.newControlDecoration;
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.newText;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.databinding.AggregateValidationStatus;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.PojoObservables;
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.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.resource.JFaceResources;
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.Button;
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.Text;
import com.amazonaws.eclipse.core.AwsToolkitCore;
import com.amazonaws.eclipse.databinding.BooleanValidator;
import com.amazonaws.eclipse.databinding.ChainValidator;
import com.amazonaws.eclipse.databinding.DecorationChangeListener;
import com.amazonaws.eclipse.databinding.NotEmptyValidator;
import com.amazonaws.eclipse.opsworks.OpsWorksPlugin;
import com.amazonaws.eclipse.opsworks.deploy.wizard.model.DeployProjectToOpsworksWizardDataModel;
import com.amazonaws.eclipse.opsworks.deploy.wizard.model.DeployProjectToOpsworksWizardDataModel.EnvironmentVariable;
import com.amazonaws.eclipse.opsworks.deploy.wizard.model.DeployProjectToOpsworksWizardDataModel.SslConfiguration;
import com.amazonaws.eclipse.opsworks.deploy.wizard.model.S3ApplicationSource;
import com.amazonaws.eclipse.opsworks.explorer.image.OpsWorksExplorerImages;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.Bucket;
public class NewAppConfigurationComposite extends Composite {
private DeployProjectToOpsworksWizardDataModel dataModel;
private final DataBindingContext bindingContext;
private final AggregateValidationStatus aggregateValidationStatus;
/**
* @see #setValidationStatusChangeListener(IChangeListener)
* @see #removeValidationStatusChangeListener()
*/
private IChangeListener validationStatusChangeListener;
private IObservableValue bucketNameSelected = new WritableValue();
private ISWTObservableValue bucketNameComboObservable;
private ISWTObservableValue keyNameTextObservable;
private ISWTObservableValue enableSslCheckBoxObservable;
private ISWTObservableValue certTextObservable;
private ISWTObservableValue chainTextObservable;
private ISWTObservableValue privateKeyTextObservable;
private Combo bucketNameCombo;
private Text keyNameText;
private ControlDecoration keyNameTextDecoration;
private Button enableSslCheckBox;
private Text certText;
private Text chainText;
private Text privateKeyText;
/* Constants */
private static final String LOADING = "Loading...";
private static final String NONE_FOUND = "None found";
NewAppConfigurationComposite(Composite parent, DeployProjectToOpsworksWizardDataModel dataModel) {
super(parent, SWT.NONE);
this.dataModel = dataModel;
// Clear S3ApplicationSource
this.dataModel.setS3ApplicationSource(new S3ApplicationSource());
this.bindingContext = new DataBindingContext();
this.aggregateValidationStatus = new AggregateValidationStatus(
bindingContext, AggregateValidationStatus.MAX_SEVERITY);
setLayout(new GridLayout(1, false));
createControls(this);
bindControls();
initializeValidators();
initializeDefaults();
loadS3BucketsAsync();
}
/**
* Set listener that will be notified whenever the validation status of this
* composite is updated. This method removes the listener (if any) that is
* currently registered to this composite - only one listener instance is
* allowed at a time.
*/
public synchronized void setValidationStatusChangeListener(IChangeListener listener) {
removeValidationStatusChangeListener();
validationStatusChangeListener = listener;
aggregateValidationStatus.addChangeListener(listener);
}
/**
* @see #setValidationStatusChangeListener(IChangeListener)
*/
public synchronized void removeValidationStatusChangeListener() {
if (validationStatusChangeListener != null) {
aggregateValidationStatus.removeChangeListener(validationStatusChangeListener);
validationStatusChangeListener = null;
}
}
public void updateValidationStatus() {
Iterator<?> iterator = bindingContext.getBindings().iterator();
while (iterator.hasNext()) {
Binding binding = (Binding)iterator.next();
binding.updateTargetToModel();
}
}
private void createControls(Composite parent) {
createBasicSettingSection(parent);
createApplicationSourceSection(parent);
createEnvironmentVariablesSection(parent);
createCustomDomainsSection(parent);
createSslSettingsSection(parent);
}
private void bindControls() {
bucketNameComboObservable = SWTObservables
.observeSelection(bucketNameCombo);
bindingContext.bindValue(
bucketNameComboObservable,
PojoObservables.observeValue(
dataModel.getS3ApplicationSource(),
S3ApplicationSource.BUCKET_NAME));
keyNameTextObservable = SWTObservables
.observeText(keyNameText, SWT.Modify);
bindingContext.bindValue(
keyNameTextObservable,
PojoObservables.observeValue(
dataModel.getS3ApplicationSource(),
S3ApplicationSource.KEY_NAME));
enableSslCheckBoxObservable = SWTObservables
.observeSelection(enableSslCheckBox);
bindingContext.bindValue(
enableSslCheckBoxObservable,
PojoObservables.observeValue(
dataModel,
DeployProjectToOpsworksWizardDataModel.ENABLE_SSL));
certTextObservable = SWTObservables
.observeText(certText, SWT.Modify);
bindingContext.bindValue(
certTextObservable,
PojoObservables.observeValue(
dataModel.getSslConfiguration(),
SslConfiguration.CERTIFICATE));
chainTextObservable = SWTObservables
.observeText(chainText, SWT.Modify);
bindingContext.bindValue(
chainTextObservable,
PojoObservables.observeValue(
dataModel.getSslConfiguration(),
SslConfiguration.CHAIN));
privateKeyTextObservable = SWTObservables
.observeText(privateKeyText, SWT.Modify);
bindingContext.bindValue(
privateKeyTextObservable,
PojoObservables.observeValue(
dataModel.getSslConfiguration(),
SslConfiguration.PRIVATE_KEY));
}
private void initializeValidators() {
bindingContext.addValidationStatusProvider(new ChainValidator<Boolean>(
bucketNameSelected,
new BooleanValidator("Please select a bucket for storing the application source")));
ChainValidator<String> keyNameValidator = new ChainValidator<String>(
keyNameTextObservable,
new NotEmptyValidator("Please provide a valid S3 key name"));
bindingContext.addValidationStatusProvider(keyNameValidator);
new DecorationChangeListener(keyNameTextDecoration,
keyNameValidator.getValidationStatus());
}
private void initializeDefaults() {
keyNameTextObservable.setValue("archive.zip");
enableSslCheckBoxObservable.setValue(false);
certTextObservable.setValue("");
chainTextObservable.setValue("");
privateKeyTextObservable.setValue("");
}
private void createBasicSettingSection(Composite parent) {
Group settingsGroup = newGroup(parent, "Settings");
settingsGroup.setLayout(new GridLayout(3, true));
newFillingLabel(settingsGroup, "Name").setFont(JFaceResources.getBannerFont());
newFillingLabel(settingsGroup, dataModel.getNewJavaAppName(), 2);
newFillingLabel(settingsGroup, "Type").setFont(JFaceResources.getBannerFont());
newFillingLabel(settingsGroup, "Java", 2);
}
private void createApplicationSourceSection(Composite parent) {
Group applicationSourceGroup = newGroup(parent, "Application Source");
applicationSourceGroup.setLayout(new GridLayout(3, true));
newFillingLabel(
applicationSourceGroup,
"Specify the S3 location where your application source will be stored.",
3);
newFillingLabel(applicationSourceGroup, "Bucket name").setFont(JFaceResources.getBannerFont());
bucketNameCombo = newCombo(applicationSourceGroup, 2);
bucketNameCombo.setEnabled(false);
bucketNameSelected.setValue(false);
newFillingLabel(applicationSourceGroup, "Key name").setFont(JFaceResources.getBannerFont());
keyNameText = newText(applicationSourceGroup, "", 2);
keyNameTextDecoration = newControlDecoration(keyNameText,
"Enter a valid S3 key name");
}
private void loadS3BucketsAsync() {
Display.getDefault().syncExec(new Runnable() {
public void run() {
bucketNameCombo.setItems(new String[] {LOADING});
bucketNameCombo.select(0);
}
});
Display.getDefault().asyncExec(new Runnable() {
public void run() {
try {
AmazonS3 client = AwsToolkitCore.getClientFactory()
.getS3ClientByEndpoint("https://s3.amazonaws.com/");
List<Bucket> allBuckets = client.listBuckets();
if (allBuckets.isEmpty()) {
bucketNameCombo.setItems(new String[] {NONE_FOUND});
bucketNameSelected.setValue(false);
} else {
List<String> allBucketNames = new LinkedList<String>();
for (Bucket bucket : allBuckets) {
allBucketNames.add(bucket.getName());
}
bucketNameCombo.setItems(allBucketNames.toArray(new String[allBucketNames.size()]));
bucketNameCombo.select(0);
bucketNameCombo.setEnabled(true);
bucketNameSelected.setValue(true);
}
} catch (Exception e) {
OpsWorksPlugin.getDefault().reportException(
"Failed to load S3 buckets.", e);
}
}
});
}
private void createEnvironmentVariablesSection(Composite parent) {
final Group envVarGroup = newGroup(parent, "Environment Variables");
envVarGroup.setLayout(new GridLayout(4, true));
newFillingLabel(
envVarGroup,
"Specify the name and value of the environment variables for your application",
4);
// Input box for new variables
final Text keyText = newText(envVarGroup);
keyText.setMessage("Key");
final Text valueText = newText(envVarGroup);
valueText.setMessage("Value");
final Button checkBox = newCheckbox(envVarGroup, "Protected value", 1);
Button addButton = new Button(envVarGroup, SWT.PUSH);
addButton.setImage(OpsWorksPlugin.getDefault().getImageRegistry()
.get(OpsWorksExplorerImages.IMG_ADD));
addButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent arg0) {
if (keyText.getText().isEmpty() && valueText.getText().isEmpty()) {
return;
}
EnvironmentVariable newVar = new EnvironmentVariable();
newVar.setKey(keyText.getText());
newVar.setValue(valueText.getText());
newVar.setSecure(checkBox.getSelection());
dataModel.addEnvironmentVariable(newVar);
addNewEnvironmentVariable(envVarGroup, newVar);
keyText.setText("");
valueText.setText("");
checkBox.setSelection(false);
NewAppConfigurationComposite.this.layout(true, true);
}
});
// Added variables
for (EnvironmentVariable envVar : dataModel.getEnvironmentVariables()) {
addNewEnvironmentVariable(envVarGroup, envVar);
}
}
private void addNewEnvironmentVariable(Group parentGroup, EnvironmentVariable variable) {
newFillingLabel(parentGroup, variable.getKey()).setFont(JFaceResources.getBannerFont());
newFillingLabel(parentGroup, variable.getValue());
newFillingLabel(parentGroup, variable.isSecure() ? "(Protected)" : "(Not protected)", 2);
}
private void createCustomDomainsSection(Composite parent) {
final Group domainsGroup = newGroup(parent, "Custom Domains");
domainsGroup.setLayout(new GridLayout(2, true));
newFillingLabel(
domainsGroup,
"Add one or more custom domains for your application",
2);
// Input box for new domains
final Text domainText = newText(domainsGroup);
domainText.setMessage("www.example.com");
Button addButton = new Button(domainsGroup, SWT.PUSH);
addButton.setImage(OpsWorksPlugin.getDefault().getImageRegistry()
.get(OpsWorksExplorerImages.IMG_ADD));
addButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent arg0) {
if (domainText.getText().isEmpty()) {
return;
}
String newDomain = domainText.getText();
dataModel.addCustomDomain(newDomain);
newFillingLabel(domainsGroup, "[+] " + newDomain, 2);
NewAppConfigurationComposite.this.layout(true, true);
}
});
// Added domains
for (String domain : dataModel.getCustomDomains()) {
newFillingLabel(domainsGroup, "[+] " + domain, 2);
}
}
private void createSslSettingsSection(Composite parent) {
Group sslSettingsGroup = newGroup(parent, "SSL Settings");
enableSslCheckBox = newCheckbox(sslSettingsGroup, "SSL enabled", 1);
final Group advancedSslSettings = newGroup(sslSettingsGroup, "");
advancedSslSettings.setLayout(new GridLayout(2, true));
newFillingLabel(advancedSslSettings, "SSL certificate").setFont(JFaceResources.getBannerFont());
certText = newText(advancedSslSettings, "");
certText.setEnabled(false);
newFillingLabel(advancedSslSettings, "SSL certificate key").setFont(JFaceResources.getBannerFont());
privateKeyText = newText(advancedSslSettings, "");
privateKeyText.setEnabled(false);
newFillingLabel(advancedSslSettings, "SSL certificates of CA").setFont(JFaceResources.getBannerFont());
chainText = newText(advancedSslSettings, "");
chainText.setEnabled(false);
enableSslCheckBox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent arg0) {
boolean enabled = enableSslCheckBox.getSelection();
certText.setEnabled(enabled);
privateKeyText.setEnabled(enabled);
chainText.setEnabled(enabled);
}
});
}
}