/**
* Copyright (c) Microsoft Corporation
* <p/>
* All rights reserved.
* <p/>
* MIT License
* <p/>
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* <p/>
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
* the Software.
* <p/>
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.microsoft.intellij.ui;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.ui.TitlePanel;
import com.intellij.openapi.ui.ValidationInfo;
import com.interopbridges.tools.windowsazure.OSFamilyType;
import com.interopbridges.tools.windowsazure.WindowsAzurePackageType;
import com.interopbridges.tools.windowsazure.WindowsAzureProjectManager;
import com.microsoft.intellij.AzurePlugin;
import com.microsoft.intellij.AzureSettings;
import com.microsoft.intellij.runnable.LoadAccountWithProgressBar;
import com.microsoft.intellij.ui.components.DefaultDialogWrapper;
import com.microsoft.intellij.ui.components.WindowsAzurePage;
import com.microsoft.intellij.ui.util.UIUtils;
import com.microsoft.intellij.ui.util.UIUtils.ElementWrapper;
import com.microsoft.intellij.util.MethodUtils;
import com.microsoft.intellij.util.PluginUtil;
import com.microsoft.intellij.wizards.WizardCacheManager;
import com.microsoft.windowsazure.management.compute.models.HostedServiceListResponse;
import com.microsoftopentechnologies.azurecommons.deploy.util.PublishData;
import com.microsoftopentechnologies.azurecommons.deploy.wizard.ConfigurationEventArgs;
import com.microsoftopentechnologies.azuremanagementutil.model.KeyName;
import com.microsoftopentechnologies.azuremanagementutil.model.StorageService;
import com.microsoftopentechnologies.azuremanagementutil.model.StorageServices;
import com.microsoftopentechnologies.azuremanagementutil.model.Subscription;
import org.jdesktop.swingx.JXHyperlink;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.microsoft.intellij.AzurePlugin.log;
import static com.microsoft.intellij.ui.messages.AzureBundle.message;
import static com.microsoft.windowsazure.management.compute.models.HostedServiceListResponse.HostedService;
public class DeployWizardDialog extends WindowsAzurePage {
private JPanel contentPane;
private JButton importButton;
private JComboBox subscriptionCombo;
private JXHyperlink subLink;
private JComboBox storageAccountCmb;
private JButton newStorageAccountBtn;
private JComboBox hostedServiceCombo;
private JButton newHostedServiceBtn;
private JComboBox targetOS;
private JComboBox deployStateCmb;
private JCheckBox unpublishChBox;
private JTextField userName;
private JPasswordField userPassword;
private JPasswordField confirmPassword;
private JCheckBox conToDplyChkBtn;
private JLabel userPasswordLbl;
private JLabel confirmPasswordLbl;
private JXHyperlink encLink;
private final Module myModule;
private PublishData publishData;
private HostedService currentHostedService;
private StorageService currentStorageAccount;
private WindowsAzurePackageType deployMode = WindowsAzurePackageType.CLOUD;
private String defaultLocation;
public ArrayList<String> newServices = new ArrayList<String>();
private String deployFileName;
private String deployConfigFileName;
private WindowsAzureProjectManager waProjManager;
public DeployWizardDialog(Module module) {
super(module.getProject());
this.myModule = module;
loadProject();
init();
}
@Override
protected void init() {
super.init();
myOKAction.putValue(Action.NAME, "Publish");
importButton.addActionListener(createImportSubscriptionAction());
subscriptionCombo.addItemListener(createSubscriptionComboListener());
subLink.setAction(createSubLinkAction());
UIUtils.populateSubscriptionCombo(subscriptionCombo);
AzureSettings azureSettings = AzureSettings.getSafeInstance(myModule.getProject());
if (!azureSettings.isSubscriptionLoaded()) {
doLoadPreferences();
// reload information if its new session.
AzureSettings.getSafeInstance(myModule.getProject()).loadStorage();
MethodUtils.prepareListFromPublishData(myModule.getProject());
azureSettings.setSubscriptionLoaded(true);
UIUtils.populateSubscriptionCombo(subscriptionCombo);
if ((subscriptionCombo.getSelectedItem() != null)) {
loadDefaultWizardValues();
}
}
storageAccountCmb.addItemListener(createStorageAccountListener());
populateStorageAccounts();
newStorageAccountBtn.addActionListener(createNewStorageAccountListener());
hostedServiceCombo.addItemListener(createHostedServiceComboListener());
populateHostedServices();
newHostedServiceBtn.addActionListener(createNewHostedServiceListener());
populateTargetOs();
deployStateCmb.setModel(new DefaultComboBoxModel(new String[]{message("deplStaging"), message("deplProd")}));
deployStateCmb.addItemListener(createDeployStateCmbListener());
userName.getDocument().addDocumentListener(createUserNameListener());
encLink.setAction(createEncLinkAction());
boolean isSubPresent = subscriptionCombo.getSelectedItem() != null;
setComponentState(isSubPresent);
if (isSubPresent) {
// load cached subscription, cloud service & storage account
loadDefaultWizardValues();
}
loadDefaultRDPValues();
}
private DocumentListener createUserNameListener() {
return new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
setEnableRemAccess(e.getDocument().getLength() > 0);
}
@Override
public void removeUpdate(DocumentEvent e) {
setEnableRemAccess(e.getDocument().getLength() > 0);
}
@Override
public void changedUpdate(DocumentEvent e) {
setEnableRemAccess(e.getDocument().getLength() > 0);
}
};
}
private ActionListener createNewStorageAccountListener() {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ElementWrapper<PublishData> subscription = (ElementWrapper<PublishData>) subscriptionCombo.getSelectedItem();
if (subscription != null) {
PublishData publishData = ((ElementWrapper<PublishData>) subscriptionCombo.getSelectedItem()).getValue();
int maxStorageAccounts = publishData.getCurrentSubscription().getMaxStorageAccounts();
String currentSubscriptionId = publishData.getCurrentSubscription().getId();
if (maxStorageAccounts > publishData.getStoragesPerSubscription().get(currentSubscriptionId).size()) {
NewStorageAccountDialog storageAccountDialog = new NewStorageAccountDialog(subscription.getKey(), myModule.getProject());
if (defaultLocation != null) { // user has created a hosted service before a storage account
storageAccountDialog.setDefaultLocation(defaultLocation);
}
storageAccountDialog.show();
if (storageAccountDialog.isOK()) {
populateStorageAccounts();
UIUtils.selectByText(storageAccountCmb, storageAccountDialog.getStorageAccountName());
defaultLocation = WizardCacheManager.getStorageAccountFromCurrentPublishData(storageAccountDialog.getStorageAccountName()).getStorageAccountProperties().getLocation();
}
} else {
PluginUtil.displayErrorDialog(message("storageAccountsLimitTitle"), message("storageAccountsLimitErr"));
}
}
}
};
}
private Action createSubLinkAction() {
return new AbstractAction(message("linkLblSub")) {
@Override
public void actionPerformed(ActionEvent e) {
final DefaultDialogWrapper subscriptionsDialog = new DefaultDialogWrapper(myModule.getProject(), new SubscriptionsPanel(myModule.getProject()));
subscriptionsDialog.show();
/*
* Update data in every case.
* No need to check which button (OK/Cancel)
* has been pressed as change is permanent
* even though user presses cancel
* according to functionality.
*/
// doLoadPreferences();
UIUtils.populateSubscriptionCombo(subscriptionCombo);
// update cache of publish data object
if (subscriptionCombo.getSelectedItem() != null) {
publishData = ((ElementWrapper<PublishData>) subscriptionCombo.getSelectedItem()).getValue();
}
// enable and disable components.
setComponentState((subscriptionCombo.getSelectedItem() != null));
}
};
}
private Action createEncLinkAction() {
return new AbstractAction(message("linkLblEnc")) {
@Override
public void actionPerformed(ActionEvent e) {
// open remote access dialog
DefaultDialogWrapper remoteAccess = new DefaultDialogWrapper(myModule.getProject(),
new WARemoteAccessPanel(myModule, true, userName.getText(), String.valueOf(userPassword.getPassword()),
String.valueOf(confirmPassword.getPassword())));
remoteAccess.show();
if (remoteAccess.isOK()) {
loadDefaultRDPValues();
/*
* To handle the case, if you typed
* password on Publish wizard --> Encryption link
* Remote access --> OK --> Toggle password text boxes
*/
// isPwdChanged = false;
}
}
};
}
protected void doOKAction() {
handlePageComplete();
super.doOKAction();
}
/**
* Initialize {@link WindowsAzureProjectManager} object
* according to selected project.
*/
private void loadProject() {
try {
String modulePath = PluginUtil.getModulePath(myModule);
File projectDir = new File(modulePath);
waProjManager = WindowsAzureProjectManager.load(projectDir);
} catch (Exception e) {
log(message("projLoadEr"), e);
}
}
private void doLoadPreferences() {
LoadAccountWithProgressBar task = new LoadAccountWithProgressBar(myModule.getProject());
ProgressManager.getInstance().runProcessWithProgressSynchronously(task, "Loading Account Settings...", true, myModule.getProject());
}
private ActionListener createNewHostedServiceListener() {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
UIUtils.ElementWrapper<PublishData> subscriptionItem = (UIUtils.ElementWrapper<PublishData>) subscriptionCombo.getSelectedItem();
if (subscriptionItem != null) {
PublishData publishData = subscriptionItem.getValue();
int maxHostedServices = publishData.getCurrentSubscription().getMaxHostedServices();
String currentSubscriptionId = publishData.getCurrentSubscription().getId();
if (maxHostedServices > publishData.getServicesPerSubscription().get(currentSubscriptionId).size()) {
NewHostedServiceDialog hostedServiceDialog = new NewHostedServiceDialog();
if (defaultLocation != null) { // user has created a storage account before creating the hosted service
hostedServiceDialog.setDefaultLocation(defaultLocation);
}
hostedServiceDialog.show();
if (hostedServiceDialog.isOK()) {
populateHostedServices();
newServices.add(hostedServiceDialog.getHostedServiceName());
UIUtils.selectByText(hostedServiceCombo, hostedServiceDialog.getHostedServiceName());
defaultLocation = WizardCacheManager.getHostedServiceFromCurrentPublishData(hostedServiceDialog.getHostedServiceName()).
getProperties().getLocation();
}
} else {
PluginUtil.displayErrorDialog(message("hostServLimitTitle"), message("hostServLimitErr"));
}
}
}
};
}
private ItemListener createStorageAccountListener() {
return new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED && storageAccountCmb.getSelectedItem() != null) {
currentStorageAccount = ((ElementWrapper<StorageService>) storageAccountCmb.getSelectedItem()).getValue();
}
// setPageComplete(validatePageComplete());
}
};
}
private ItemListener createHostedServiceComboListener() {
return new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
ElementWrapper<HostedService> selectedItem = (ElementWrapper<HostedService>) hostedServiceCombo.getSelectedItem();
currentHostedService = selectedItem == null ? null : selectedItem.getValue();
// setPageComplete(validatePageComplete());
}
}
};
}
private void populateTargetOs() {
List<String> osNames = new ArrayList<String>();
for (OSFamilyType osType : OSFamilyType.values()) {
osNames.add(osType.getName());
}
targetOS.setModel(new DefaultComboBoxModel(osNames.toArray(new String[osNames.size()])));
}
private ItemListener createSubscriptionComboListener() {
return new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
publishData = UIUtils.changeCurrentSubAsPerCombo((JComboBox) e.getSource());
if (storageAccountCmb != null && publishData != null) {
populateStorageAccounts();
populateHostedServices();
setComponentState((subscriptionCombo.getSelectedItem() != null));
}
// setPageComplete(validatePageComplete());
}
};
}
private ActionListener createImportSubscriptionAction() {
return new ActionListener() {
public void actionPerformed(ActionEvent e) {
final ImportSubscriptionDialog importSubscriptionDialog = new ImportSubscriptionDialog();
importSubscriptionDialog.show();
if (importSubscriptionDialog.isOK()) {
importBtn(importSubscriptionDialog.getPublishSettingsPath());
}
}
};
}
private ItemListener createDeployStateCmbListener() {
return new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
String deployState = (String) ((JComboBox) e.getSource()).getSelectedItem();
if (deployState.equalsIgnoreCase(message("deplProd"))) {
unpublishChBox.setSelected(false);
}
// setPageComplete(validatePageComplete());
}
};
}
private void importBtn(String fileName) {
if (fileName != null && !fileName.isEmpty()) {
File file = new File(fileName);
PublishData publishDataToCache = MethodUtils.handlePublishSettings(file, myModule.getProject());
if (publishDataToCache == null) {
return;
}
/*
* logic to set un-pubilsh check box to true
* when ever importing publish settings
* file for the first time.
*/
if (subscriptionCombo.getItemCount() == 0) {
unpublishChBox.setSelected(true);
}
UIUtils.populateSubscriptionCombo(subscriptionCombo);
//
// int selection = 0;
// selection = findSelectionIndex(publishDataToCache);
//
// subscriptionCombo.select(selection);
// WizardCacheManager.setCurrentPublishData(publishDataToCache);
//
setComponentState((subscriptionCombo.getSelectedItem() != null));
// // Make centralized storage registry.
// MethodUtils.prepareListFromPublishData();
}
}
/**
* Method loads configured remote access values
* on wizard page.
*/
private void loadDefaultRDPValues() {
try {
// to update project manager object
loadProject();
String uname = waProjManager.getRemoteAccessUsername();
if (uname != null && !uname.isEmpty()) {
userName.setText(uname);
try {
String pwd = waProjManager.getRemoteAccessEncryptedPassword();
/*
* If its dummy password,
* then do not show it on UI
*/
if (pwd.equals(message("remAccDummyPwd")) || pwd.isEmpty()) {
userPassword.setText("");
confirmPassword.setText("");
} else {
userPassword.setText(pwd);
confirmPassword.setText(pwd);
}
setEnableRemAccess(true);
} catch (Exception e) {
userPassword.setText("");
confirmPassword.setText("");
}
} else {
userName.setText("");
setEnableRemAccess(false);
}
} catch (Exception e) {
userName.setText("");
setEnableRemAccess(false);
}
/*
* Non windows OS then disable components,
* but keep values as it is
*/
if (!AzurePlugin.IS_WINDOWS) {
userName.setEnabled(false);
userPassword.setEnabled(false);
confirmPassword.setEnabled(false);
userPasswordLbl.setEnabled(false);
confirmPasswordLbl.setEnabled(false);
conToDplyChkBtn.setEnabled(false);
}
}
private void loadDefaultWizardValues() {
try {
loadProject();
// Get global properties from package.xml
String subId = waProjManager.getPublishSubscriptionId();
String cloudServiceName = waProjManager.getPublishCloudServiceName();
String storageAccName = waProjManager.getPublishStorageAccountName();
if (subId != null && !subId.isEmpty()) {
String subName = WizardCacheManager.findSubscriptionNameBySubscriptionId(subId);
if (subName != null && !subName.isEmpty()) {
UIUtils.selectByText(subscriptionCombo, subName);
publishData = UIUtils.changeCurrentSubAsPerCombo(subscriptionCombo);
if (publishData != null) {
populateStorageAccounts();
populateHostedServices();
setComponentState(subscriptionCombo.getSelectedItem() != null);
UIUtils.selectByText(hostedServiceCombo, cloudServiceName);
UIUtils.selectByText(storageAccountCmb, storageAccName);
}
}
}
try {
String deploymentSlot = waProjManager.getPublishDeploymentSlot().toString();
if (deploymentSlot != null && !deploymentSlot.isEmpty()) {
UIUtils.selectByText(deployStateCmb, deploymentSlot);
}
} catch (Exception e) {
// ignore.
// Mostly it would be IllegalArgumentException if valid deployment string not specified
}
try {
boolean overwriteDeployment = waProjManager.getPublishOverwritePreviousDeployment();
unpublishChBox.setSelected(overwriteDeployment);
} catch (Exception e) {
// ignore
}
} catch (Exception e) {
log(message("error"), e);
}
}
/**
* Enable or disable password fields.
*
* @param status
*/
private void setEnableRemAccess(boolean status) {
userPassword.setEnabled(status);
confirmPassword.setEnabled(status);
userPasswordLbl.setEnabled(status);
confirmPasswordLbl.setEnabled(status);
conToDplyChkBtn.setEnabled(status);
if (!status) {
userPassword.setText("");
confirmPassword.setText("");
conToDplyChkBtn.setSelected(false);
}
}
/**
* Enable or disable components related to
* publish settings.
*
* @param enabled
*/
private void setComponentState(boolean enabled) {
subscriptionCombo.setEnabled(enabled);
storageAccountCmb.setEnabled(enabled);
newStorageAccountBtn.setEnabled(enabled);
hostedServiceCombo.setEnabled(enabled);
targetOS.setEnabled(enabled);
if (!enabled) {
hostedServiceCombo.removeAllItems();
storageAccountCmb.removeAllItems();
}
deployStateCmb.setEnabled(enabled);
newHostedServiceBtn.setEnabled(enabled);
unpublishChBox.setEnabled(enabled);
}
protected void populateStorageAccounts() {
if (publishData != null) {
Object currentSelection = storageAccountCmb.getSelectedItem();
Subscription currentSubscription = publishData.getCurrentSubscription();
StorageServices storageServices = publishData.getStoragesPerSubscription().get(currentSubscription.getId());
storageAccountCmb.removeAllItems();
if (storageServices != null && !storageServices.isEmpty()) {
for (StorageService storageService : storageServices) {
storageAccountCmb.addItem(new ElementWrapper<StorageService>(storageService.getServiceName(), storageService));
}
}
if (currentSelection != null) {
storageAccountCmb.setSelectedItem(currentSelection);
}
}
}
public void populateHostedServices() {
if (publishData != null) {
Object currentSelection = hostedServiceCombo.getSelectedItem();
Subscription currentSubscription = publishData.getCurrentSubscription();
java.util.List<HostedServiceListResponse.HostedService> hostedServices = publishData.getServicesPerSubscription().get(currentSubscription.getId());
hostedServiceCombo.removeAllItems();
if (hostedServices != null && !hostedServices.isEmpty()) {
for (HostedServiceListResponse.HostedService hsd : hostedServices) {
hostedServiceCombo.addItem(new ElementWrapper<HostedServiceListResponse.HostedService>(hsd.getServiceName(), hsd));
}
if (currentSelection != null) {
hostedServiceCombo.setSelectedItem(currentSelection);
}
}
}
}
@Override
protected JComponent createCenterPanel() {
return contentPane;
}
protected JComponent createTitlePane() {
return new TitlePanel(message("deplWizTitle"), "");
}
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 400);
}
@Nullable
@Override
protected ValidationInfo doValidate() {
if (publishData == null) {
return new ValidationInfo(message("deplFillSubsciptionId"), subscriptionCombo);
}
if (currentStorageAccount == null) {
return new ValidationInfo(message("deplFillStorageAcc"), storageAccountCmb);
}
if (currentHostedService == null) {
return new ValidationInfo(message("deplFillHostedServiceMsg"), hostedServiceCombo);
}
/*
* Validation for remote access settings.
*/
if (!userName.getText().isEmpty()) {
char[] pwd = userPassword.getPassword();
if (pwd == null || pwd.length == 0) {
// password is empty
return new ValidationInfo(message("rdpPasswordEmpty"), userPassword);
} else {
char[] confirm = confirmPassword.getPassword();
if (confirm == null || confirm.length == 0) {
// confirm password is empty
return new ValidationInfo(message("rdpConfirmPasswordEmpty"), confirmPassword);
} else {
if (!Arrays.equals(pwd, confirm)) {
// password and confirm password do not match.
return new ValidationInfo(message("rdpPasswordsDontMatch"), confirmPassword);
}
}
}
}
return null;
}
private void handlePageComplete() {
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.DEPLOY_MODE, deployMode));
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.SUBSCRIPTION, publishData));
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.CONFIG_HTTPS_LINK, waProjManager.getSSLInfoIfUnique() != null ? "true" : "false"));
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.STORAGE_ACCOUNT,
currentStorageAccount));
// Always set key to primary
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.STORAGE_ACCESS_KEY,
KeyName.Primary.toString()));
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.DEPLOY_STATE,
deployStateCmb.getSelectedItem()));
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.UN_PUBLISH,
unpublishChBox.isSelected()));
deployFileName = constructDeployFilePath(message("cspckDefaultFileName"));
deployConfigFileName = constructDeployFilePath(message("cscfgDefaultFileName"));
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.DEPLOY_FILE,
deployFileName));
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.DEPLOY_CONFIG_FILE,
deployConfigFileName));
fireConfigurationEvent(new ConfigurationEventArgs(this,
ConfigurationEventArgs.HOSTED_SERVICE,
currentHostedService));
}
private String constructDeployFilePath(String fileName) {
String moduleLocation = PluginUtil.getModulePath(myModule);
return moduleLocation + File.separator + message("deployDir") + File.separator + fileName;
}
/**
* Method returns new services names, if created by user.
*
* @return
*/
public ArrayList<String> getNewServices() {
return newServices;
}
public String getTargetOSName() {
return (String) targetOS.getSelectedItem();
}
public String getRdpUname() {
return userName.getText();
}
public String getRdpPwd() {
return new String(userPassword.getPassword());
}
public boolean getConToDplyChkStatus() {
return conToDplyChkBtn.isSelected();
}
@Override
public String getHelpId() {
return "publish_project_command";
}
}