/** * 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.wizards; import com.interopbridges.tools.windowsazure.WindowsAzurePackageType; import com.microsoft.intellij.AzurePlugin; import com.microsoft.intellij.rest.WindowsAzureRestUtils; import com.microsoft.intellij.ui.components.WindowsAzurePage; import com.microsoft.windowsazure.Configuration; import com.microsoft.windowsazure.management.compute.models.HostedServiceCreateParameters; import com.microsoft.windowsazure.management.compute.models.HostedServiceGetDetailedResponse; import com.microsoft.windowsazure.management.compute.models.HostedServiceListResponse.HostedService; import com.microsoft.windowsazure.management.compute.models.ServiceCertificateListResponse.Certificate; import com.microsoft.windowsazure.management.models.LocationsListResponse.Location; import com.microsoft.windowsazure.management.storage.models.StorageAccountCreateParameters; import com.microsoftopentechnologies.azurecommons.deploy.model.CertificateUpload; import com.microsoftopentechnologies.azurecommons.deploy.model.CertificateUploadList; import com.microsoftopentechnologies.azurecommons.deploy.model.DeployDescriptor; import com.microsoftopentechnologies.azurecommons.deploy.model.RemoteDesktopDescriptor; import com.microsoftopentechnologies.azurecommons.deploy.tasks.*; import com.microsoftopentechnologies.azurecommons.deploy.util.PublishData; import com.microsoftopentechnologies.azurecommons.deploy.wizard.ConfigurationEventArgs; import com.microsoftopentechnologies.azurecommons.deploy.wizard.ConfigurationEventListener; import com.microsoftopentechnologies.azurecommons.deploy.wizard.WizardCacheManagerUtilMethods; import com.microsoftopentechnologies.azurecommons.exception.RestAPIException; import com.microsoftopentechnologies.azurecommons.wacommonutil.FileUtil; import com.microsoftopentechnologies.azurecommons.wacommonutil.PreferenceSetUtil; 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 com.microsoftopentechnologies.azuremanagementutil.rest.WindowsAzureServiceManagement; import com.microsoftopentechnologies.azuremanagementutil.rest.WindowsAzureStorageServices; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; import java.util.*; import java.util.concurrent.*; import static com.microsoft.intellij.AzurePlugin.log; import static com.microsoft.intellij.ui.messages.AzureBundle.message; public final class WizardCacheManager { private static final WizardCacheManager INSTANCE = new WizardCacheManager(); private static final List<PublishData> PUBLISHS = new ArrayList<PublishData>(); private static PublishData currentPublishData; private static KeyName currentAccessKey; private static String currentStorageService; private static String currentHostedService; private static String deployFile; private static String deployConfigFile; private static String deployState; private static WindowsAzurePackageType deployMode; private static String unpublish; private static RemoteDesktopDescriptor remoteDesktopDescriptor; private static CertificateUploadList certList; private static boolean displayHttpsLink = false; private static Map<String, String> publishSettingsPerSubscriptionMap = new HashMap<String, String>(); public static WizardCacheManager getInstrance() { return INSTANCE; } public static List<CertificateUpload> getList() { return certList.getList(); } private WizardCacheManager() { WindowsAzurePage.addConfigurationEventListener(new ConfigurationEventListener() { @Override public void onConfigurationChanged(ConfigurationEventArgs config) { try { notifyConfiguration(config); } catch (RestAPIException e) { log(message("error"), e); } } }); } public static DeployDescriptor collectConfiguration() { DeployDescriptor deployDescriptor = new DeployDescriptor(deployMode, currentPublishData.getCurrentSubscription().getId(), getCurrentStorageAcount(), currentAccessKey, getCurentHostedService(), deployFile, deployConfigFile, deployState, remoteDesktopDescriptor, checkSchemaVersionAndReturnUrl(), unpublish, certList, displayHttpsLink, currentPublishData.getCurrentConfiguration()); remoteDesktopDescriptor = null; return deployDescriptor; } public static WindowsAzureStorageServices createStorageServiceHelper() { return WizardCacheManagerUtilMethods.createStorageServiceHelper(currentPublishData, currentStorageService, currentAccessKey); } public static WindowsAzureServiceManagement createServiceManagementHelper() { return WizardCacheManagerUtilMethods.createServiceManagementHelper(currentPublishData); } public static List<Location> getLocation() { return WizardCacheManagerUtilMethods.getLocation(currentPublishData); } public static String getCurrentDeplyFile() { return deployFile; } public static boolean getDisplayHttpsLink() { return displayHttpsLink; } public static String getCurrentDeployConfigFile() { return deployConfigFile; } public static String getCurrentDeplyState() { return deployState; } public static String getUnpublish() { return unpublish; } public static RemoteDesktopDescriptor getCurrentRemoteDesktopDescriptor() { return remoteDesktopDescriptor; } public static PublishData getCurrentPublishData() { return currentPublishData; } public static Collection<PublishData> getPublishDatas() { return PUBLISHS; } public static Subscription findSubscriptionByName(String subscriptionName) { return WizardCacheManagerUtilMethods.findSubscriptionByName(subscriptionName, PUBLISHS); } public static PublishData findPublishDataBySubscriptionId(String subscriptionId) { return WizardCacheManagerUtilMethods.findPublishDataBySubscriptionId(subscriptionId, PUBLISHS); } public static String findSubscriptionNameBySubscriptionId(String subscriptionId) { return WizardCacheManagerUtilMethods.findSubscriptionNameBySubscriptionId(subscriptionId, PUBLISHS); } public static void removeSubscription(String subscriptionId) { if (subscriptionId == null) { return; } PublishData publishData = findPublishDataBySubscriptionId(subscriptionId); if (publishData == null) { return; } List<Subscription> subs = publishData.getPublishProfile().getSubscriptions(); int index = WizardCacheManagerUtilMethods.getIndexOfPublishData(subscriptionId, PUBLISHS); for (int i = 0; i < subs.size(); i++) { Subscription s = subs.get(i); if (s.getSubscriptionID().equals(subscriptionId)) { publishData.getPublishProfile().getSubscriptions().remove(i); PUBLISHS.set(index, publishData); if (publishData.getPublishProfile().getSubscriptions().size() == 0) { PUBLISHS.remove(publishData); /* * If all subscriptions are removed * set current subscription to null. */ setCurrentPublishData(null); } break; } } } public static void changeCurrentSubscription(PublishData publishData, String subscriptionId) { WizardCacheManagerUtilMethods.changeCurrentSubscription(publishData, subscriptionId); } public static StorageService getCurrentStorageAcount() { return WizardCacheManagerUtilMethods.getCurrentStorageAcount(currentPublishData, currentStorageService); } public static HostedService getCurentHostedService() { return WizardCacheManagerUtilMethods.getCurentHostedService(currentPublishData, currentHostedService); } public static HostedService getHostedServiceFromCurrentPublishData(final String hostedServiceName) { return WizardCacheManagerUtilMethods.getHostedServiceFromCurrentPublishData(hostedServiceName, currentPublishData); } /** * Method uses REST API and returns already uploaded certificates * from currently selected cloud service on wizard. * * @return */ public static List<Certificate> fetchUploadedCertificates() { return WizardCacheManagerUtilMethods.fetchUploadedCertificates(currentPublishData, currentHostedService); } public static HostedService createHostedService(HostedServiceCreateParameters createHostedService) throws Exception { HostedService hostedService = WizardCacheManagerUtilMethods.createHostedService(createHostedService, currentPublishData); currentPublishData.getServicesPerSubscription().get(currentPublishData.getCurrentSubscription().getId()).add(hostedService); return hostedService; } public static StorageService createStorageAccount(StorageAccountCreateParameters accountParameters) throws Exception { Subscription subscription = currentPublishData.getCurrentSubscription(); StorageService storageAccount = WizardCacheManagerUtilMethods.createStorageAccount(accountParameters, currentPublishData, AzurePlugin.prefFilePath); // remove previous mock if existed currentPublishData.getStoragesPerSubscription().get(subscription.getId()).remove(accountParameters.getName()); currentPublishData.getStoragesPerSubscription().get(subscription.getId()).add(storageAccount); return storageAccount; } public static boolean isHostedServiceNameAvailable(final String hostedServiceName) throws Exception { return WizardCacheManagerUtilMethods.isHostedServiceNameAvailable(hostedServiceName, currentPublishData); } public static boolean isStorageAccountNameAvailable(final String storageAccountName) throws Exception { return WizardCacheManagerUtilMethods.isStorageAccountNameAvailable(storageAccountName, currentPublishData); } public static StorageService createStorageServiceMock(String storageAccountNameToCreate, String storageAccountLocation, String description) { StorageService storageService = WizardCacheManagerUtilMethods.createStorageServiceMock(storageAccountNameToCreate, storageAccountLocation, description); currentPublishData.getStoragesPerSubscription().get(currentPublishData.getCurrentSubscription().getId()).add(storageService); return storageService; } public static HostedService createHostedServiceMock(String hostedServiceNameToCreate, String hostedServiceLocation, String description) { Subscription subscription = currentPublishData.getCurrentSubscription(); HostedService hostedService = WizardCacheManagerUtilMethods.createHostedServiceMock(hostedServiceNameToCreate, hostedServiceLocation, description); currentPublishData.getServicesPerSubscription().get(subscription.getId()).add(hostedService); return hostedService; } public static List<HostedService> getHostedServices() { return WizardCacheManagerUtilMethods.getHostedServices(currentPublishData); } private void notifyConfiguration(ConfigurationEventArgs config) throws RestAPIException { if (ConfigurationEventArgs.DEPLOY_FILE.equals(config.getKey())) { deployFile = config.getValue().toString(); } else if (ConfigurationEventArgs.DEPLOY_CONFIG_FILE.equals(config.getKey())) { deployConfigFile = config.getValue().toString(); } else if (ConfigurationEventArgs.DEPLOY_STATE.equals(config.getKey())) { deployState = config.getValue().toString(); } else if (ConfigurationEventArgs.SUBSCRIPTION.equals(config.getKey())) { PublishData publishData = (PublishData) config.getValue(); if (publishData.isInitialized() == false && publishData.isInitializing().compareAndSet(false, true)) { // CacheAccountWithProgressWindow settings = new CacheAccountWithProgressWindow(null, publishData, Display.getDefault().getActiveShell(), null); // Display.getDefault().syncExec(settings); } } else if (ConfigurationEventArgs.HOSTED_SERVICE.equals(config.getKey())) { HostedService hostedService = (HostedService) config.getValue(); if (hostedService != null) currentHostedService = hostedService.getServiceName(); } else if (ConfigurationEventArgs.STORAGE_ACCOUNT.equals(config.getKey())) { StorageService storageService = (StorageService) config.getValue(); if (storageService != null) { currentStorageService = storageService.getServiceName(); } } else if (ConfigurationEventArgs.REMOTE_DESKTOP.equals(config.getKey())) { remoteDesktopDescriptor = (RemoteDesktopDescriptor) config.getValue(); } else if (ConfigurationEventArgs.CERTIFICATES.equals(config.getKey())) { certList = (CertificateUploadList) config.getValue(); } else if (ConfigurationEventArgs.DEPLOY_MODE.equals(config.getKey())) { deployMode = (WindowsAzurePackageType) config.getValue(); } else if (ConfigurationEventArgs.UN_PUBLISH.equals(config.getKey())) { unpublish = config.getValue().toString(); } else if (ConfigurationEventArgs.STORAGE_ACCESS_KEY.equals(config.getKey())) { String value = config.getValue().toString(); if (value != null && !value.isEmpty()) { currentAccessKey = KeyName.valueOf(value); } else { currentAccessKey = KeyName.Primary; } } else if (ConfigurationEventArgs.CONFIG_HTTPS_LINK.equals(config.getKey())) { String value = config.getValue().toString(); if (value != null && !value.isEmpty()) { displayHttpsLink = Boolean.parseBoolean(value.trim()); } } } public static HostedServiceGetDetailedResponse getHostedServiceWithDeployments(String hostedService) throws Exception { return WizardCacheManagerUtilMethods.getHostedServiceWithDeployments(hostedService, currentPublishData); } public static void setCurrentPublishData(PublishData currentSubscription2) { currentPublishData = currentSubscription2; } public static void cachePublishData(File publishSettingsFile, PublishData publishData, LoadingAccoutListener listener) throws RestAPIException, IOException { boolean canceled = false; List<Subscription> subscriptions = null; int OPERATIONS_TIMEOUT = 60 * 5; if (publishData == null) { return; } else { subscriptions = publishData.getPublishProfile().getSubscriptions(); } if (subscriptions == null) { return; } String schemaVer = publishData.getPublishProfile().getSchemaVersion(); boolean isNewSchema = schemaVer != null && !schemaVer.isEmpty() && schemaVer.equalsIgnoreCase("2.0"); // URL if schema version is 1.0 String url = publishData.getPublishProfile().getUrl(); Map<String, Configuration> configurationPerSubscription = new HashMap<String, Configuration>(); for (Subscription subscription : subscriptions) { if (isNewSchema) { // publishsetting file is of schema version 2.0 url = subscription.getServiceManagementUrl(); } if (url == null || url.isEmpty()) { try { url = PreferenceSetUtil.getManagementURL(PreferenceSetUtil.getSelectedPreferenceSetName(AzurePlugin.prefFilePath), AzurePlugin.prefFilePath); url = url.substring(0, url.lastIndexOf("/")); } catch (Exception e) { log(e.getMessage()); } } Configuration configuration = (publishSettingsFile == null) ? WindowsAzureRestUtils.loadConfiguration(subscription.getId(), url) : WindowsAzureRestUtils.getConfiguration(publishSettingsFile, subscription.getId()); configurationPerSubscription.put(subscription.getId(), configuration); if (publishSettingsFile != null) { //copy file to user home String outFile = System.getProperty("user.home") + File.separator + ".azure" + File.separator + publishSettingsFile.getName(); try { // copy file to user home FileUtil.writeFile(new FileInputStream(publishSettingsFile), new FileOutputStream(outFile)); // put an entry into global cache publishSettingsPerSubscriptionMap.put(subscription.getId(), outFile); } catch (IOException e) { // Ignore error e.printStackTrace(); } } } publishData.setConfigurationPerSubscription(configurationPerSubscription); if (publishData.isInitialized() == false && publishData.isInitializing().compareAndSet(false, true)) { List<Future<?>> loadServicesFutures = null; Future<?> loadSubscriptionsFuture = null; try { List<Subscription> subBackup = publishData.getPublishProfile().getSubscriptions(); // thread pool size is number of subscriptions ScheduledExecutorService subscriptionThreadPool = Executors.newScheduledThreadPool(subscriptions.size()); LoadingSubscriptionTask loadingSubscriptionTask = new LoadingSubscriptionTask(publishData); loadingSubscriptionTask.setSubscriptionIds(subscriptions); if (listener != null) { loadingSubscriptionTask.addLoadingAccountListener(listener); } loadSubscriptionsFuture = subscriptionThreadPool.submit(new LoadingTaskRunner(loadingSubscriptionTask)); loadSubscriptionsFuture.get(OPERATIONS_TIMEOUT, TimeUnit.SECONDS); /* * add explicitly management URL and certificate which was removed * Changes are did to support both publish setting schema versions. */ if (isNewSchema) { for (int i = 0; i < subBackup.size(); i++) { publishData.getPublishProfile().getSubscriptions().get(i). setServiceManagementUrl(subBackup.get(i).getServiceManagementUrl()); publishData.getPublishProfile().getSubscriptions().get(i). setManagementCertificate(subBackup.get(i).getManagementCertificate()); } } if (publishData.getCurrentSubscription() == null && publishData.getPublishProfile().getSubscriptions().size() > 0) { publishData.setCurrentSubscription(publishData.getPublishProfile().getSubscriptions().get(0)); } // thread pool size is 3 to load hosted services, locations and storage accounts. ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3); loadServicesFutures = new ArrayList<Future<?>>(); // Hosted services LoadingHostedServicesTask loadingHostedServicesTask = new LoadingHostedServicesTask(publishData); if (listener != null) { loadingHostedServicesTask.addLoadingAccountListener(listener); } Future<?> submitHostedServices = threadPool.submit(new LoadingTaskRunner(loadingHostedServicesTask)); loadServicesFutures.add(submitHostedServices); // locations LoadingLocationsTask loadingLocationsTask = new LoadingLocationsTask(publishData); if (listener != null) { loadingLocationsTask.addLoadingAccountListener(listener); } Future<?> submitLocations = threadPool.submit(new LoadingTaskRunner(loadingLocationsTask)); loadServicesFutures.add(submitLocations); // storage accounts LoadingStorageAccountTask loadingStorageAccountTask = new LoadingStorageAccountTask(publishData); if (listener != null) { loadingStorageAccountTask.addLoadingAccountListener(listener); } Future<?> submitStorageAccounts = threadPool.submit(new LoadingTaskRunner(loadingStorageAccountTask)); loadServicesFutures.add(submitStorageAccounts); for (Future<?> future : loadServicesFutures) { future.get(OPERATIONS_TIMEOUT, TimeUnit.SECONDS); } try { String chinaMngmntUrl = PreferenceSetUtil.getManagementURL("windowsazure.cn (China)", AzurePlugin.prefFilePath); chinaMngmntUrl = chinaMngmntUrl.substring(0, chinaMngmntUrl.lastIndexOf("/")); if (url.equals(chinaMngmntUrl)) { for (Subscription sub : publishData.getPublishProfile().getSubscriptions()) { StorageServices services = publishData.getStoragesPerSubscription().get(sub.getId()); for (StorageService strgService : services) { List<URI> endpoints = strgService.getStorageAccountProperties().getEndpoints(); for (int i = 0; i < endpoints.size(); i++) { String uri = endpoints.get(i).toString(); if (uri.startsWith("https://")) { endpoints.set(i, URI.create(uri.replaceFirst("https://", "http://"))); } } } } } } catch (Exception e) { // Ignore error } } catch (InterruptedException e) { if (loadSubscriptionsFuture != null) { loadSubscriptionsFuture.cancel(true); } if (loadServicesFutures != null) { for (Future<?> future : loadServicesFutures) { future.cancel(true); } } canceled = true; } catch (ExecutionException e) { } catch (TimeoutException e) { } } if (publishData.getPublishProfile().getSubscriptions().size() > 0) { if (!empty(publishData) && !canceled) { removeDuplicateSubscriptions(publishData); PUBLISHS.add(publishData); publishData.isInitializing().compareAndSet(true, false); currentPublishData = publishData; } } } private static void removeDuplicateSubscriptions(PublishData publishData) { Set<String> subscriptionIdsToRemove = new HashSet<String>(); List<Subscription> subscriptionsOfPublishDataToCache = publishData.getPublishProfile().getSubscriptions(); for (Subscription subscriptionOfPublishDataToCache : subscriptionsOfPublishDataToCache) { for (PublishData pd : PUBLISHS) { for (Subscription existingSubscription : pd.getPublishProfile().getSubscriptions()) { if (existingSubscription.getId().equals(subscriptionOfPublishDataToCache.getId())) { subscriptionIdsToRemove.add(existingSubscription.getId()); } } } } for (String subscriptionId : subscriptionIdsToRemove) { removeSubscription(subscriptionId); } List<PublishData> emptyPublishDatas = new ArrayList<PublishData>(); for (PublishData pd : PUBLISHS) { if (pd.getPublishProfile().getSubscriptions().isEmpty()) { emptyPublishDatas.add(pd); } } for (PublishData emptyData : emptyPublishDatas) { PUBLISHS.remove(emptyData); } } private static boolean empty(PublishData data) { return WizardCacheManagerUtilMethods.empty(data); } public static StorageService getStorageAccountFromCurrentPublishData(String storageAccountName) { return WizardCacheManagerUtilMethods.getStorageAccountFromCurrentPublishData(storageAccountName, currentPublishData); } private static String checkSchemaVersionAndReturnUrl() { return WizardCacheManagerUtilMethods.checkSchemaVersionAndReturnUrl(currentPublishData); } public static String getPublishSettingsPath(String subscriptionID) { return publishSettingsPerSubscriptionMap.get(subscriptionID); } public static Map<String, String> getPublishSettingsPerSubscription() { return publishSettingsPerSubscriptionMap; } public static void addPublishSettingsPerSubscription(Map<String, String> publishSettingsPerSubscription) { publishSettingsPerSubscriptionMap.putAll(publishSettingsPerSubscription); } }