diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/src/com/microsoft/intellij/helpers/UIHelperImpl.java b/PluginsAndFeatures/azure-toolkit-for-intellij/src/com/microsoft/intellij/helpers/UIHelperImpl.java index 81c2b485e9..390fd19d0e 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/src/com/microsoft/intellij/helpers/UIHelperImpl.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/src/com/microsoft/intellij/helpers/UIHelperImpl.java @@ -65,6 +65,7 @@ import com.microsoft.intellij.helpers.webapp.DeploymentSlotPropertyViewProvider; import com.microsoft.intellij.helpers.webapp.WebAppPropertyViewProvider; import com.microsoft.intellij.ui.util.UIUtils; +import com.microsoft.intellij.util.PluginUtil; import com.microsoft.tooling.msservices.components.DefaultLoader; import com.microsoft.tooling.msservices.helpers.UIHelper; import com.microsoft.tooling.msservices.model.storage.Queue; @@ -758,6 +759,11 @@ public String showInputDialog(Component component, String message, String title, return runFromDispatchThread(() -> Messages.showInputDialog(component, message, title, icon)); } + @Override + public void showInfoNotification(String title, String message) { + PluginUtil.showInfoNotification(title, message); + } + private static T runFromDispatchThread(Supplier supplier) { if (ApplicationManager.getApplication().isDispatchThread()) { return supplier.get(); diff --git a/PluginsAndFeatures/azure-toolkit-for-intellij/src/com/microsoft/intellij/util/PluginUtil.java b/PluginsAndFeatures/azure-toolkit-for-intellij/src/com/microsoft/intellij/util/PluginUtil.java index b0f76dfe37..fdc5f9e015 100644 --- a/PluginsAndFeatures/azure-toolkit-for-intellij/src/com/microsoft/intellij/util/PluginUtil.java +++ b/PluginsAndFeatures/azure-toolkit-for-intellij/src/com/microsoft/intellij/util/PluginUtil.java @@ -202,6 +202,12 @@ public static void showErrorNotificationProject(Project project, String title, S message, NotificationType.ERROR).notify(project); } + public static void showInfoNotification(String title, String message) { + Notification notification = new Notification(NOTIFICATION_GROUP_ID, title, + message, NotificationType.INFORMATION); + Notifications.Bus.notify(notification); + } + public static void showWarnNotification(String title, String message) { Notification notification = new Notification(NOTIFICATION_GROUP_ID, title, message, NotificationType.WARNING); diff --git a/Utils/azure-explorer-common/src/com/microsoft/tooling/msservices/helpers/UIHelper.java b/Utils/azure-explorer-common/src/com/microsoft/tooling/msservices/helpers/UIHelper.java index 99f591697f..42299abee1 100644 --- a/Utils/azure-explorer-common/src/com/microsoft/tooling/msservices/helpers/UIHelper.java +++ b/Utils/azure-explorer-common/src/com/microsoft/tooling/msservices/helpers/UIHelper.java @@ -154,4 +154,8 @@ default boolean showYesNoDialog(Component component, String message, String titl default String showInputDialog(Component component, String message, String title, Icon icon) { return (String) JOptionPane.showInputDialog(component, message, title, JOptionPane.QUESTION_MESSAGE, icon, null, null); } + + default void showInfoNotification(String title, String message) { + + } } diff --git a/Utils/azure-explorer-common/src/com/microsoft/tooling/msservices/serviceexplorer/azure/AzureModule.java b/Utils/azure-explorer-common/src/com/microsoft/tooling/msservices/serviceexplorer/azure/AzureModule.java index ae9818037e..df9d93ca2b 100644 --- a/Utils/azure-explorer-common/src/com/microsoft/tooling/msservices/serviceexplorer/azure/AzureModule.java +++ b/Utils/azure-explorer-common/src/com/microsoft/tooling/msservices/serviceexplorer/azure/AzureModule.java @@ -26,6 +26,8 @@ import com.microsoft.azuretools.authmanage.AuthMethodManager; import com.microsoft.azuretools.authmanage.SubscriptionManager; import com.microsoft.azuretools.authmanage.models.SubscriptionDetail; +import com.microsoft.azuretools.enums.ErrorEnum; +import com.microsoft.azuretools.exception.AzureRuntimeException; import com.microsoft.azuretools.azurecommons.helpers.AzureCmdException; import com.microsoft.azuretools.azurecommons.helpers.NotNull; import com.microsoft.azuretools.azurecommons.helpers.Nullable; @@ -121,6 +123,9 @@ private static String composeName() { .filter(SubscriptionDetail::isSelected).collect(Collectors.toList()); return String.format("%s (%s)", BASE_MODULE_NAME, getAccountDescription(selectedSubscriptions)); + } catch (AzureRuntimeException e) { + DefaultLoader.getUIHelper().showInfoNotification( + ERROR_GETTING_SUBSCRIPTIONS_TITLE, ErrorEnum.getDisplayMessageByCode(e.getCode())); } catch (Exception e) { final String msg = String.format(ERROR_GETTING_SUBSCRIPTIONS_MESSAGE, e.getMessage()); DefaultLoader.getUIHelper().showException(msg, e, ERROR_GETTING_SUBSCRIPTIONS_TITLE, false, true); diff --git a/Utils/azuretools-core/src/com/microsoft/azuretools/enums/ErrorEnum.java b/Utils/azuretools-core/src/com/microsoft/azuretools/enums/ErrorEnum.java new file mode 100644 index 0000000000..844f8b0780 --- /dev/null +++ b/Utils/azuretools-core/src/com/microsoft/azuretools/enums/ErrorEnum.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) Microsoft Corporation + * + * All rights reserved. + * + * MIT License + * + * 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: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * 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.azuretools.enums; + +/** + * Enums of backend errors for azure tools. + */ +public enum ErrorEnum { + UNKNOWN_HOST_EXCEPTION(100000, "Encountered an unknown host exception.", + "It seems you have an unstable network at the moment, please try again when network is available."), + SOCKET_TIMEOUT_EXCEPTION(100002, "Encountered a socket timeout exception.", + "Timeout when accessing azure, please try your operation again."), + FAILED_TO_GET_ACCESS_TOKEN_BY_CLI(100003, "Failed to get access token by Azure CLI command.", + "Failed to get access token, please try to login Azure CLI using 'az login' and try again."), + ; + + private int errorCode; + private String errorMessage; + private String displyMessage; + + ErrorEnum(int errorCode, String errorMessage, String displayMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + this.displyMessage = displayMessage; + } + + public int getErrorCode() { + return errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public String getDisplyMessage() { + return displyMessage; + } + + public static String getDisplayMessageByCode(int code) { + for (ErrorEnum e : ErrorEnum.values()) { + if (e.getErrorCode() == code) { + return e.getDisplyMessage(); + } + } + throw new IllegalArgumentException(String.format("Not found enum for code: %s", code)); + } + +} diff --git a/Utils/azuretools-core/src/com/microsoft/azuretools/exception/AzureRuntimeException.java b/Utils/azuretools-core/src/com/microsoft/azuretools/exception/AzureRuntimeException.java new file mode 100644 index 0000000000..21d844bba3 --- /dev/null +++ b/Utils/azuretools-core/src/com/microsoft/azuretools/exception/AzureRuntimeException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) Microsoft Corporation + * + * All rights reserved. + * + * MIT License + * + * 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: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * 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.azuretools.exception; + +import com.microsoft.azuretools.enums.ErrorEnum; + +/** + * RuntinmeException for azure tools. + */ +public class AzureRuntimeException extends RuntimeException { + + private int code; + + public AzureRuntimeException(ErrorEnum errorEnum) { + super(errorEnum.getErrorMessage()); + this.code = errorEnum.getErrorCode(); + } + + public AzureRuntimeException(int code) { + this.code = code; + } + + public AzureRuntimeException(int code, String message) { + super(message); + this.code = code; + } + + public AzureRuntimeException(int code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureCliAzureManager.java b/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureCliAzureManager.java index 07bf1f36a2..af1ddf3914 100644 --- a/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureCliAzureManager.java +++ b/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureCliAzureManager.java @@ -34,7 +34,9 @@ import com.microsoft.azuretools.authmanage.CommonSettings; import com.microsoft.azuretools.authmanage.Environment; import com.microsoft.azuretools.authmanage.models.AuthMethodDetails; +import com.microsoft.azuretools.exception.AzureRuntimeException; import com.microsoft.azuretools.azurecommons.helpers.Nullable; +import com.microsoft.azuretools.enums.ErrorEnum; import com.microsoft.azuretools.utils.CommandUtils; import com.microsoft.azuretools.utils.Pair; import org.apache.commons.lang.ObjectUtils; @@ -188,6 +190,9 @@ private Pair getAccessTokenViaCli(String tid, @Nullable String.format(CLI_TOKEN_FORMAT_ACCESSOR, tid) : String.format(CLI_TOKEN_FORMAT_ACCESSOR_RESOURCE, tid, resource); final String jsonToken = CommandUtils.exec(command); + if (StringUtils.isBlank(jsonToken)) { + throw new AzureRuntimeException(ErrorEnum.FAILED_TO_GET_ACCESS_TOKEN_BY_CLI); + } final Map objectMap = JsonUtils.fromJson(jsonToken, Map.class); final String strToken = (String) objectMap.get(CLI_TOKEN_PROP_ACCESS_TOKEN); final String strTime = (String) objectMap.get(CLI_TOKEN_PROP_EXPIRATION); diff --git a/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureManagerBase.java b/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureManagerBase.java index 48c073ed78..344c1465a2 100644 --- a/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureManagerBase.java +++ b/Utils/azuretools-core/src/com/microsoft/azuretools/sdkmanage/AzureManagerBase.java @@ -22,6 +22,7 @@ package com.microsoft.azuretools.sdkmanage; +import com.google.common.base.Throwables; import com.microsoft.azure.AzureEnvironment; import com.microsoft.azure.arm.resources.AzureConfigurable; import com.microsoft.azure.credentials.AzureTokenCredentials; @@ -30,11 +31,9 @@ import com.microsoft.azure.management.appplatform.v2019_05_01_preview.implementation.AppPlatformManager; import com.microsoft.azure.management.resources.Subscription; import com.microsoft.azure.management.resources.Tenant; -import com.microsoft.azuretools.authmanage.CommonSettings; -import com.microsoft.azuretools.authmanage.Environment; -import com.microsoft.azuretools.authmanage.RefreshableTokenCredentials; -import com.microsoft.azuretools.authmanage.SubscriptionManager; -import com.microsoft.azuretools.authmanage.SubscriptionManagerPersist; +import com.microsoft.azuretools.authmanage.*; +import com.microsoft.azuretools.exception.AzureRuntimeException; +import com.microsoft.azuretools.enums.ErrorEnum; import com.microsoft.azuretools.telemetry.TelemetryInterceptor; import com.microsoft.azuretools.utils.AzureRegisterProviderNamespaces; import com.microsoft.azuretools.utils.Pair; @@ -42,6 +41,7 @@ import rx.Observable; import java.io.IOException; +import java.net.UnknownHostException; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -51,10 +51,7 @@ import java.util.logging.Logger; import java.util.stream.Collectors; -import static com.microsoft.azuretools.authmanage.Environment.CHINA; -import static com.microsoft.azuretools.authmanage.Environment.GERMAN; -import static com.microsoft.azuretools.authmanage.Environment.GLOBAL; -import static com.microsoft.azuretools.authmanage.Environment.US_GOVERNMENT; +import static com.microsoft.azuretools.authmanage.Environment.*; /** * Created by vlashch on 1/27/17. @@ -249,14 +246,20 @@ private List getSubscriptions(Azure.Authenticated tenantAuthentica } private List getTenants(Azure.Authenticated authentication) { - return authentication.tenants().listAsync() - .onErrorResumeNext(err -> { - LOGGER.warning(err.getMessage()); - return Observable.empty(); - }) - .toList() - .toBlocking() - .singleOrDefault(Collections.emptyList()); + try { + return authentication.tenants().listAsync() + .toList() + .toBlocking() + .singleOrDefault(Collections.emptyList()); + } catch (Exception err) { + LOGGER.warning(Throwables.getStackTraceAsString(err)); + if (Throwables.getCausalChain(err).stream().filter(e -> e instanceof UnknownHostException).count() > 0) { + throw new AzureRuntimeException(ErrorEnum.UNKNOWN_HOST_EXCEPTION); + } else if (err instanceof AzureRuntimeException) { + throw err; + } + return Collections.emptyList(); + } } protected Azure.Authenticated authTenant(String tenantId) {